diff --git a/.github/workflows/api_format.yaml b/.github/workflows/api_format.yaml index 371526c2ca..df9c1b81e9 100644 --- a/.github/workflows/api_format.yaml +++ b/.github/workflows/api_format.yaml @@ -19,6 +19,8 @@ env: ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} jobs: backport: diff --git a/.github/workflows/dependabot.yaml b/.github/workflows/dependabot.yaml index 821cf1a663..52e7f2c45d 100644 --- a/.github/workflows/dependabot.yaml +++ b/.github/workflows/dependabot.yaml @@ -23,6 +23,8 @@ env: ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} jobs: dependabot_build: diff --git a/.github/workflows/nightly-docker-build.yaml b/.github/workflows/nightly-docker-build.yaml index f42fa8647f..2956574926 100644 --- a/.github/workflows/nightly-docker-build.yaml +++ b/.github/workflows/nightly-docker-build.yaml @@ -15,6 +15,8 @@ env: ALGOLIA_INDEX_NAME: "madeup-index" PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} jobs: build: diff --git a/.github/workflows/post_release.yaml b/.github/workflows/post_release.yaml index 55662514d8..2e3be37168 100644 --- a/.github/workflows/post_release.yaml +++ b/.github/workflows/post_release.yaml @@ -18,6 +18,8 @@ env: ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} jobs: diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index 7e1f7de682..e508f32ae5 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -22,6 +22,8 @@ env: ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} jobs: run-ci: diff --git a/.github/workflows/release-branch-pr.yaml b/.github/workflows/release-branch-pr.yaml index 394588131f..a9f50ede3d 100644 --- a/.github/workflows/release-branch-pr.yaml +++ b/.github/workflows/release-branch-pr.yaml @@ -19,6 +19,8 @@ env: GITHUB_BRANCH: ${{ github.ref_name }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} concurrency: diff --git a/.github/workflows/release-preview.yaml b/.github/workflows/release-preview.yaml index 9c2c5f2c6c..be3119b9c2 100644 --- a/.github/workflows/release-preview.yaml +++ b/.github/workflows/release-preview.yaml @@ -18,6 +18,8 @@ env: ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} concurrency: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d407dc997b..63c8407353 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,12 +7,14 @@ on: schedule: - cron: '0 20 * * 1-5' # At 12:00 PM PST (8 PM UTC), Monday through Friday - cron: '0 5 * * 2-6' # At 9:00 PM PST (5 AM UTC next day), Monday through Friday + - cron: '0 20 * * 6' # At 12:00 PM PST (8 PM UTC next day), Saturday - Due to Security Buletin Publication + - cron: '0 20 * * 0' # At 12:00 PM PST (8 PM UTC next day), Sunday - Due to Security Buletin Publication workflow_dispatch: inputs: useGitHubHostedLargeRunner: description: 'Use the GitHub-hosted large runner. Allowed values are true or false. Caution - this results in additional charges to the organization.' required: false - default: false + default: 'false' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -27,6 +29,8 @@ env: ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} concurrency: diff --git a/.github/workflows/screenshot_capture.yaml b/.github/workflows/screenshot_capture.yaml index 6e599cefbd..23d94271d8 100644 --- a/.github/workflows/screenshot_capture.yaml +++ b/.github/workflows/screenshot_capture.yaml @@ -21,6 +21,8 @@ env: ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} jobs: diff --git a/.github/workflows/versions_robot.yaml b/.github/workflows/versions_robot.yaml index 7db30a1b81..9a5ca6db04 100644 --- a/.github/workflows/versions_robot.yaml +++ b/.github/workflows/versions_robot.yaml @@ -22,7 +22,10 @@ env: ALGOLIA_SEARCH_KEY: ${{ secrets.ALGOLIA_SEARCH_KEY }} ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} PALETTE_API_KEY: ${{ secrets.PALETTE_API_KEY }} - GITHUB_BRANCH: ${{ github.ref_name }} + GITHUB_BRANCH: ${{ github.ref_name }} + DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} jobs: run-ci: diff --git a/.github/workflows/visual-comparison.yaml b/.github/workflows/visual-comparison.yaml index 9576b49dcf..71768d609b 100644 --- a/.github/workflows/visual-comparison.yaml +++ b/.github/workflows/visual-comparison.yaml @@ -17,6 +17,8 @@ env: ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} HTML_REPORT_URL_PATH: reports/${{ github.head_ref }}/${{ github.run_id }}/${{ github.run_attempt }} DISABLE_PACKS_INTEGRATIONS: ${{ secrets.DISABLE_PACKS_INTEGRATIONS }} + DISABLE_SECURITY_INTEGRATIONS: ${{ secrets.DISABLE_SECURITY_INTEGRATIONS }} + DSO_AUTH_TOKEN: ${{ secrets.DSO_AUTH_TOKEN }} concurrency: diff --git a/.gitignore b/.gitignore index 0904aa9ff5..16193946d9 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,10 @@ docs/api-content/api-docs/v1/sidebar.* docs/api-content/api-docs/edge-v1/*.mdx docs/api-content/api-docs/edge-v1/sidebar.* +# Security Bulletins (Autogenerated) + +docs/docs-content/security-bulletins/reports/*.md + # Versions Content versions.json versioned_docs/ @@ -71,6 +75,7 @@ _partials/index.ts # Ignore statoc/img/packs static/img/packs +static/data/security-bulletins/* .vale-config/ diff --git a/.prettierignore b/.prettierignore index 7e33410237..462ae7b456 100644 --- a/.prettierignore +++ b/.prettierignore @@ -13,6 +13,7 @@ docs/api-content/**/*.json tsconfig.json src/components/IconMapper/dynamicFontAwesomeImports.* docs/docs-content/security-bulletins/cve-reports.md +docs/docs-content/security-bulletins/reports/*.md # Ignore partials _partials/ diff --git a/Makefile b/Makefile index 067867b03d..bdc7116038 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ initialize: ## Initialize the repository dependencies npx husky-init vale sync -clean: ## Clean common artifacts +clean: clean-security ## Clean common artifacts npm run clear && npm run clean-api-docs rm -rfv build @@ -56,6 +56,10 @@ clean-packs: ## Clean supplemental packs and pack images rm -rf .docusaurus/packs-integrations/api_pack_response.json rm -rf .docusaurus/packs-integrations/api_repositories_response.json +clean-security: ## Clean security bulletins + rm -rf .docusaurus/security-bulletins/default/*.json + rm -rfv docs/docs-content/security-bulletins/reports/*.md + clean-api: ## Clean API docs @echo "cleaning api docs" npm run clean-api-docs @@ -80,6 +84,7 @@ init: ## Initialize npm dependencies start: ## Start a local development server make generate-partials + npm run cves npm run start start-cached-packs: ## Start a local development server with cached packs retry. diff --git a/README.md b/README.md index bb2a57f189..d539a91718 100644 --- a/README.md +++ b/README.md @@ -751,6 +751,28 @@ Below is an example of how to use the component when the URLs are different: /> page to learn more about system administrator roles. ``` +## Security Bulletins + +The security bulletins are auto-generated upon server start or the build process. The bulletins are generated by +querying an internal Spectro Cloud API. The bulletins are displayed in the security bulletins page +`https://docs.spectrocloud.com/security-bulletins/reports/`. + +The logic for generated the security bulletins is located in the [cves folder](./utils/cves/index.js). The script is +invoked before a build or a local development server start. The script will fetch the security bulletins and store the +data in the `.docusaurus/security-bulletins/default/` folder. The data is stored in the `data.json` file. + +The script will also generate each markdown file for each security bulletin. The markdown files are stored in the +`/security-bulletins/reports/` folder. + +### Disable Security Bulletins + +To disable the security bulletins, you can set the environment variable `DISABLE_SECURITY_INTEGRATIONS` to `true`. This +will stop the pre-build script from fetching the security bulletins. + +```shell +export DISABLE_SECURITY_INTEGRATIONS=true +``` + ## Packs Component The packs component is a custom component that displays all packs available in Palette SaaS by querying the Palette API diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 1b97d0a067..0000000000 --- a/babel.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - plugins: ["macros"], - presets: [require.resolve("@docusaurus/core/lib/babel/preset"), ["@babel/preset-env"], "@babel/preset-typescript"], -}; diff --git a/docs/docs-content/security-bulletins/reports/cve-2015-8855.md b/docs/docs-content/security-bulletins/reports/cve-2015-8855.md deleted file mode 100644 index c23205fd38..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2015-8855.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -sidebar_label: "CVE-2015-8855" -title: "CVE-2015-8855" -description: "Lifecycle of CVE-2015-8855" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2015-8855](https://nvd.nist.gov/vuln/detail/CVE-2015-8855) - -## Last Update - -7/31/2024 - -## NIST CVE Summary - -The semver package before 4.3.2 for Node.js allows attackers to cause a denial of service (CPU consumption) via a long -version string, aka a "regular expression denial of service (ReDoS)." - -## Our Official Summary - -This is a false positive as the CVE is in a node.js package that has the same name which is being used in the Golang -application. - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2015-8855) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2022-25883.md b/docs/docs-content/security-bulletins/reports/cve-2022-25883.md deleted file mode 100644 index 98b337ce98..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2022-25883.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -sidebar_label: "CVE-2022-25883" -title: "CVE-2022-25883" -description: "Lifecycle of CVE-2022-25883" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2022-25883](https://nvd.nist.gov/vuln/detail/CVE-2022-25883) - -## Last Update - -7/16/24 - -## NIST CVE Summary - -Versions of the package server before 7.5.2 are vulnerable to Regular Expression Denial of Service (ReDoS) via the -function new Range, when untrusted user data is provided as a range. - -## Our Official Summary - -The CVE reported in virtual cluster CAPI provider. Govulncheck reports it as non-impacting. - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2022-25883) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2022-41723.md b/docs/docs-content/security-bulletins/reports/cve-2022-41723.md deleted file mode 100644 index 5bb1ac2d3c..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2022-41723.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -sidebar_label: "CVE-2022-41723" -title: "CVE-2022-41723" -description: "Lifecycle of CVE-2022-41723" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2022-41723](https://nvd.nist.gov/vuln/detail/CVE-2022-41723) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -A maliciously crafted HTTP/2 stream could cause excessive CPU consumption in the HPACK decoder, sufficient to cause a -denial of service from a small number of small requests. - -## Our Official Summary - -CVE exists in coredns that’s being used in k8s 1.28.11. Affects only k8s version 1.28.11.For customer workload clusters, -workaround is to use k8s version 1.29+. For Palette Self Hosted cluster, a future release will upgrade to 1.29+. - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2022-41723) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2022-4450.md b/docs/docs-content/security-bulletins/reports/cve-2022-4450.md deleted file mode 100644 index 8775d74fd6..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2022-4450.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -sidebar_label: "CVE-2022-4450" -title: "CVE-2022-4450" -description: "Lifecycle of CVE-2022-4450" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -# CVE Details - -We provide the most up-to-date information below. - -## CVE Details - -[CVE-2022-4450](https://nvd.nist.gov/vuln/detail/CVE-2022-4450) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the "name" (e.g. "CERTIFICATE"), any -header data and the payload data. If the function succeeds then the "name_out", "header" and "data" arguments are -populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those -buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() -will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. -If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. - -## Our Official Summary - -This is a false positive reported by twistlock. We have confirmed this CVE is fixed in the FIPS openSSL version -1.1.1f-1ubuntu2.fips.22 that’s being used in VerteX. Additional information can be found at -[https://ubuntu.com/security/CVE-2022-4450](https://ubuntu.com/security/CVE-2022-4450) - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2022-4450) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2023-0215.md b/docs/docs-content/security-bulletins/reports/cve-2023-0215.md deleted file mode 100644 index 2dac757291..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2023-0215.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -sidebar_label: "CVE-2023-0215" -title: "CVE-2023-0215" -description: "Lifecycle of CVE-2023-0215" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2023-0215](https://nvd.nist.gov/vuln/detail/CVE-2023-0215) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -The public API function BIO\\\_new\\\_NDEF is a helper function used for streaming ASN.1 data via a BIO. It is primarily -used internally to OpenSSL to support the SMIME, CMS and PKCS7 streaming capabilities, but may also be called directly -by end user applications. - -## Our Official Summary - -This is a false positive reported by twistlock. We have confirmed this CVE is fixed in the FIPS openSSL version -1.1.1f-1ubuntu2.fips.22 that’s being used in VerteX. You can learn more at -[https://ubuntu.com/security/CVE-2023-0215](https://ubuntu.com/security/CVE-2023-0215). - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-0215) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2023-0286.md b/docs/docs-content/security-bulletins/reports/cve-2023-0286.md deleted file mode 100644 index 125f1e0304..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2023-0286.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -sidebar_label: "CVE-2023-0286" -title: "CVE-2023-0286" -description: "Lifecycle of CVE-2023-0286" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2023-0286](https://nvd.nist.gov/vuln/detail/CVE-2023-0286) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -There is a type confusion vulnerability relating to X.400 address processing inside an X.509 GeneralName. X.400 -addresses were parsed as an ASN1\\\_STRING but the public structure definition for GENERAL\\\_NAME incorrectly specified -the type of the x400Address field as ASN1\\\_TYPE. This field is subsequently interpreted by the OpenSSL function -GENERAL\\\_NAME\\\_cmp as an ASN1\\\_TYPE rather than an ASN1\\\_STRING. - -## Our Official Summary - -This is a false positive reported by twistlock only. We have confirmed this CVE is fixed in the FIPS openSSL version -that’s being used in VerteX. - -## CVE Severity - -[7.4](https://nvd.nist.gov/vuln/detail/CVE-2023-0286) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2023-0464.md b/docs/docs-content/security-bulletins/reports/cve-2023-0464.md deleted file mode 100644 index 43c8d7beca..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2023-0464.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -sidebar_label: "CVE-2023-0464" -title: "CVE-2023-0464" -description: "Lifecycle of CVE-2023-0464" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2023-0464](https://nvd.nist.gov/vuln/detail/CVE-2023-0464) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -A security vulnerability has been identified in all supported versions of OpenSSL related to the verification of X.509 -certificate chains that include policy constraints. - -## Our Official Summary - -This is a false positive reported by twistlock. We have confirmed this CVE is fixed in the FIPS openSSL version -1.1.1f-1ubuntu2.fips.22 that’s being used in VerteX. You can learn more about this CVE at -[https://ubuntu.com/security/CVE-2023-0464](https://ubuntu.com/security/CVE-2023-0464). - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-0464) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2023-39325.md b/docs/docs-content/security-bulletins/reports/cve-2023-39325.md deleted file mode 100644 index 357725b2a8..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2023-39325.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -sidebar_label: "CVE-2023-39325" -title: "CVE-2023-39325" -description: "Lifecycle of CVE-2023-39325" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2023-39325](https://nvd.nist.gov/vuln/detail/CVE-2023-39325) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -A malicious HTTP/2 client which rapidly creates requests and immediately resets them can cause excessive server resource -consumption. While the total number of requests is bounded by the http2.Server.MaxConcurrentStreams setting, resetting -an in-progress request allows the attacker to create a new request while the existing one is still executing. - -## Our Official Summary - -CVE exists in coredns that’s being used in k8s 1.28.11. For customer workload clusters, workaround is to use k8s version -1.29+. For Palette Self Hosted cluster, a future release will upgrade to 1.29+. - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-39325) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2023-44487.md b/docs/docs-content/security-bulletins/reports/cve-2023-44487.md deleted file mode 100644 index 88677c5cd3..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2023-44487.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -sidebar_label: "CVE-2023-44487" -title: "CVE-2023-44487" -description: "Lifecycle of CVE-2023-44487" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2023-44487](https://nvd.nist.gov/vuln/detail/CVE-2023-44487) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -The HTTP/2 protocol allows a denial of service (server resource consumption) because request cancellation can reset many -streams quickly, as exploited in the wild in August through October 2023\. - -## Our Official Summary - -The CVE reported in coredns and kube-vip. Govulncheck reports it as non-impacting. - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-44487) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2023-45142.md b/docs/docs-content/security-bulletins/reports/cve-2023-45142.md deleted file mode 100644 index e59db347a1..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2023-45142.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -sidebar_label: "CVE-2023-45142" -title: "CVE-2023-45142" -description: "Lifecycle of CVE-2023-45142" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2023-45142](https://nvd.nist.gov/vuln/detail/CVE-2023-45142) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -OpenTelemetry-Go Contrib is a collection of third-party packages for OpenTelemetry-Go. A handler wrapper out of the box -adds labels `http.user_agent` and `http.method` that have unbound cardinality. It leads to the server's potential memory -exhaustion when many malicious requests are sent to it. - -## Our Official Summary - -CVE exists in k8s version 1.28.11. For customer workload clusters, workaround is to use k8s version 1.29+. For Palette -Self Hosted cluster, a future release will upgrade to 1.29+. - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-45142) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2023-47108.md b/docs/docs-content/security-bulletins/reports/cve-2023-47108.md deleted file mode 100644 index 00e6df3148..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2023-47108.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -sidebar_label: "CVE-2023-47108" -title: "CVE-2023-47108" -description: "Lifecycle of CVE-2023-47108" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2023-47108](https://nvd.nist.gov/vuln/detail/CVE-2023-47108) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -OpenTelemetry-Go Contrib is a collection of third-party packages for OpenTelemetry-Go. Prior to version 0.46.0, the grpc -Unary Server Interceptor out of the box adds labels `net.peer.sock.addr` and `net.peer.sock.port` that have unbound -cardinality. It leads to the server's potential memory exhaustion when many malicious requests are sent. - -## Our Official Summary - -CVE exists in vsphere-csi 3.2.0, and kube-controller-manaer version 1.28.11. Impacts all vsphere clusters. There is no -workaround. - -## CVE Severity - -[7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-47108) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/cve-2024-21626.md b/docs/docs-content/security-bulletins/reports/cve-2024-21626.md deleted file mode 100644 index a5650cb117..0000000000 --- a/docs/docs-content/security-bulletins/reports/cve-2024-21626.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -sidebar_label: "CVE-2024-21626" -title: "CVE-2024-21626" -description: "Lifecycle of CVE-2024-21626" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[CVE-2024-21626](https://nvd.nist.gov/vuln/detail/CVE-2024-21626) - -## Last Update - -7/16/2024 - -## NIST CVE Summary - -runc is a CLI tool for spawning and running containers on Linux according to the OCI specification. In runc 1.1.11 and -earlier, due to an internal file descriptor leak, an attacker could cause a newly-spawned container process (from runc -exec) to have a working directory in the host filesystem namespace, allowing for a container escape by giving access to -the host filesystem ("attack 2"). The same attack could be used by a malicious image to allow a container process to -gain access to the host filesystem through runc run ("attack 1"). Variants of attacks 1 and 2 could be also be used to -overwrite semi-arbitrary host binaries, allowing for complete container escapes ("attack 3a" and "attack 3b"). runc -1.1.12 includes patches for this issue. - -## Our Official Summary - -CVE exists in kube-proxy 1.28.11. Affects only k8s version 1.28.11 For customer workload clusters, workaround is to use -k8s version 1.29+. For Palette Self Hosted cluster, a future release will upgrade to 1.29+. - -## CVE Severity - -[8.6](https://nvd.nist.gov/vuln/detail/CVE-2024-21626) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/ghsa-m425-mq94-257g.md b/docs/docs-content/security-bulletins/reports/ghsa-m425-mq94-257g.md deleted file mode 100644 index 2cb07ea44e..0000000000 --- a/docs/docs-content/security-bulletins/reports/ghsa-m425-mq94-257g.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -sidebar_label: "GHSA-m425-mq94-257g" -title: "GHSA-m425-mq94-257g" -description: "Lifecycle of GHSA-m425-mq94-257g" -hide_table_of_contents: true -sidebar_class_name: "hide-from-sidebar" -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -## CVE Details - -[GHSA-m425-mq94-257g](https://github.com/advisories/GHSA-m425-mq94-257g) - -## Last Update - -10/25/2023 - -## NIST CVE Summary - -The affected releases of gRPC-Go, it is possible for an attacker to send HTTP/2 requests, cancel them, and send -subsequent requests, which is valid by the HTTP/2 protocol, but would cause the gRPC-Go server to launch more concurrent -method handlers than the configured maximum stream limit. - -## Our Official Summary - -CVE exists in coredns that’s being used in k8s 1.28.11. Affects only k8s version 1.28.11. For customer workload -clusters, workaround is to use k8s version 1.29+. For Palette Self Hosted cluster, a future release will upgrade to -1.29+. - -## CVE Severity - -[7.5](https://github.com/advisories/GHSA-m425-mq94-257g) - -## Status - -Ongoing diff --git a/docs/docs-content/security-bulletins/reports/reports.md b/docs/docs-content/security-bulletins/reports/reports.md deleted file mode 100644 index e4c6ee4a98..0000000000 --- a/docs/docs-content/security-bulletins/reports/reports.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -sidebar_label: "CVE Reports" -title: "CVE Reports" -description: "Security bulletins for Common Vulnerabilities and Exposures (CVEs) related to Palette and Palette VerteX" -icon: "" -hide_table_of_contents: true -sidebar_position: 0 -toc_max_heading_level: 2 -tags: ["security", "cve"] ---- - -# Security Bulletins - -The vulnerabilities reported in this Security Bulletin include vulnerabilities within the Palette VerteX airgap solution -and third-party component vulnerabilities, which we have become aware of. These vulnerabilities are discovered via our -Bug Bounty program, our security monitoring program, or reported to us by our supply chain. - -:::info - -The CVSS Severity is provided by either the third-party service provider, or NIST CVE. We do not provide the criticality -score for third-party components. Previous security bulletins are available in the -[Security Bulletins Archive](../../unlisted/cve-reports.md). - -::: - -To fix all the vulnerabilities impacting your products, we recommends patching your instances to the latest version -regarding any third-party components. For vulnerabilities originating in our products, we will provide mitigations and -workarounds where applicable. - -Click on the CVE ID to view the full details of the vulnerability. - -| CVE ID | Initial Pub Date | Modified Date | Impacted Product & Version | Vulnerability Type | CVSS Severity | Status | -| ----------------------------------------------- | ---------------- | ------------- | -------------------------- | --------------------------------------- | -------------------------------------------------------- | ------------- | -| [CVE-2023-52425](./cve-2023-52425.md) | 02/04/2024 | 06/14/2024 | Palette 4.4.8 | Third-party component: vSphere-CSI | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-52425) | :mag: Ongoing | -| [CVE-2024-21626](./cve-2024-21626.md) | 1/3/24 | 2/18/24 | Palette 4.4.8 | Third-party component: kube-proxy | [8.6](https://nvd.nist.gov/vuln/detail/CVE-2024-21626) | :mag: Ongoing | -| [CVE-2022-41723](./cve-2022-41723.md) | 2/28/23 | 11/25/23 | Palette 4.4.8 | Third-party component: CoreDNS | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2022-41723) | :mag: Ongoing | -| [GHSA-m425-mq94-257g](./ghsa-m425-mq94-257g.md) | 10/25/23 | 10/25/23 | Palette 4.4.8 | Third-party component: CoreDNS | [7.5](https://github.com/advisories/GHSA-m425-mq94-257g) | :mag: Ongoing | -| [CVE-2022-4450](./cve-2022-4450.md) | 2/8/23 | 2/4/24 | Palette 4.4.8 | Third-party component: OpenSSL | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2022-4450) | :mag: Ongoing | -| [CVE-2023-45142](./cve-2023-45142.md) | 10/12/23 | 2/18/24 | Palette 4.4.8 | Third-party component: OpenTelemetry-Go | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-45142) | :mag: Ongoing | -| [CVE-2023-0464](./cve-2023-0464.md) | 3/22/23 | 6/21/24 | Palette 4.4.8 | Third-party component: OpenSSL | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-0464) | :mag: Ongoing | -| [CVE-2023-39325](./cve-2023-39325.md) | 10/11/23 | 4/28/24 | Palette 4.4.8 | Third-party component: Go project | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-39325) | :mag: Ongoing | -| [CVE-2023-0215](./cve-2023-0215.md) | 2/28/23 | 6/21/24 | Palette 4.4.8 | Third-party component: OpenSSL | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-0215) | :mag: Ongoing | -| [CVE-2023-47108](./cve-2023-47108.md) | 11/20/23 | 11/20/23 | Palette 4.4.8 | Third-party component: OpenTelemetry-Go | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-47108) | :mag: Ongoing | -| [CVE-2023-0286](./cve-2023-0286.md) | 2/8/23 | 2/4/24 | Palette 4.4.8 | Third-party component: OpenSSL | [7.4](https://nvd.nist.gov/vuln/detail/CVE-2023-0286) | :mag: Ongoing | -| [CVE-2020-1971](./cve-2020-1971.md) | 12/8/20 | 6/21/24 | Palette 4.4.8 | Third-party component: Ubuntu | [5.9](https://nvd.nist.gov/vuln/detail/CVE-2020-1971) | :mag: Ongoing | -| [CVE-2021-3449](./cve-2021-3449.md) | 3/25/21 | 6/21/24 | Palette 4.4.8 | Third-party component: Ubuntu | [5.9](https://nvd.nist.gov/vuln/detail/CVE-2021-3449) | :mag: Ongoing | -| [CVE-2021-3711](./cve-2021-3711.md) | 8/24/12 | 6/21/24 | Palette 4.4.8 | Third-party component: Ubuntu | [9.8](https://nvd.nist.gov/vuln/detail/CVE-2021-3711) | :mag: Ongoing | -| [CVE-2022-0778](./cve-2022-0778.md) | 3/15/22 | 6/21/24 | Palette 4.4.8 | Third-party component: Ubuntu | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2022-0778) | :mag: Ongoing | -| [CVE-2021-45079](./cve-2021-45079.md) | 1/31/22 | 11/6/23 | Palette 4.4.8 | Third-party component: Ubuntu | [9.1](https://nvd.nist.gov/vuln/detail/CVE-2021-45079) | :mag: Ongoing | -| [CVE-2023-5528](./cve-2023-5528.md) | 11/14/23 | 1/19/24 | Palette 4.4.8 | Third-party component: vSphere-CSI | [8.8](https://nvd.nist.gov/vuln/detail/CVE-2023-5528) | :mag: Ongoing | -| [CVE-2023-44487](./cve-2023-44487.md) | 10/10/23 | 6/27/24 | Palette 4.4.8 | Third-party component: CAPI | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2023-44487) | :mag: Ongoing | -| [CVE-2022-25883](./cve-2022-25883.md) | 6/21/23 | 11/6/24 | Palette 4.4.8 | Third-party component: CAPI | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2022-25883) | :mag: Ongoing | -| [CVE-2015-8855](./cve-2015-8855.md) | 1/23/17 | 1/26/12 | Palette 4.4.8 | Third-party component: CAPI | [7.5](https://nvd.nist.gov/vuln/detail/CVE-2015-8855) | :mag: Ongoing | -| [PRISMA-2022-0227](./prisma-2022-0227.md) | 9/12/23 | 9/12/23 | Palette 4.4.8 | Third-party component: vSphere-CSI | N/A | :mag: Ongoing | diff --git a/docs/docs-content/security-bulletins/reports/reports.mdx b/docs/docs-content/security-bulletins/reports/reports.mdx new file mode 100644 index 0000000000..34f43f5c75 --- /dev/null +++ b/docs/docs-content/security-bulletins/reports/reports.mdx @@ -0,0 +1,50 @@ +--- +sidebar_label: "CVE Reports" +title: "CVE Reports" +description: "Security bulletins for Common Vulnerabilities and Exposures (CVEs) related to Palette and Palette VerteX" +icon: "" +hide_table_of_contents: true +sidebar_position: 0 +toc_max_heading_level: 2 +tags: ["security", "cve"] +--- + +import CveReportsTable from "@site/src/components/CveReportsTable"; + +# Security Bulletins + +The vulnerabilities reported in this Security Bulletin include vulnerabilities within the Palette VerteX, Palette +Enterprise, and airgap environments. The reported vulnerabilities also include third-party component vulnerabilities, +which we have become aware of. These vulnerabilities are discovered via our Bug Bounty program, our security monitoring +program, or reported to us by our supply chain. + +:::info + +The CVSS Severity is provided by either the third-party service provider, or NIST CVE. We do not provide the criticality +score for third-party components. Previous security bulletins are available in the +[Security Bulletins Archive](../../unlisted/cve-reports.md). + +::: + +To fix all the vulnerabilities impacting your products, we recommend patching your instances to the latest version +regarding any third-party components. For vulnerabilities originating in our products, we will provide mitigations and +workarounds where applicable. + +### Status + +We use the following statuses to track the progress of each vulnerability. N - 2 means two versions behind the latest +versions. + +| Status | Description | +| ------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Open | The vulnerability has been identified and is pending an investigation. | +| Ongoing | The vulnerability is being investigated. | +| Fixed | The vulnerability has been addressed in the latest versions of Palette or Vertex. Previous versions (N -2) are being worked on. | +| Closed | The vulnerability has been addressed in the latest version and in N - 2 versions. | + +### CVE Reports + +By default, the table is sorted to display descending entries that were recently modified. Click on the CVE ID to view +the full details of the vulnerability. + + diff --git a/docs/docs-content/security-bulletins/security-bulletins.md b/docs/docs-content/security-bulletins/security-bulletins.md index 148d3b6240..16303124de 100644 --- a/docs/docs-content/security-bulletins/security-bulletins.md +++ b/docs/docs-content/security-bulletins/security-bulletins.md @@ -9,6 +9,8 @@ sidebar_custom_props: tags: ["security", "cve"] --- +import CveReportsTable from "@site/src/components/CveReportsTable"; + We aim to provide you with the most up-to-date information about the security of our products and services. No matter how carefully engineered the services are, from time to time, it may be necessary to notify you of security and privacy events with our services, including the security notifications we receive related to the third-party components we @@ -16,9 +18,10 @@ utilize in our products and services. ## Security Bulletins -We release [security bulletins](./reports/reports.md) on a monthly and ad-hoc basis addressing security vulnerabilities -in our software or related third-party components, describing their remediation when available, and providing links to -the applicable updates for affected software when available. + +We release on a daily and ad-hoc basis addressing security vulnerabilities in our software or +related third-party components, describing their remediation when available, and providing links to the applicable +updates for affected software when available. ## Security Advisories @@ -29,4 +32,4 @@ security bulletin. ## Resources -- [Security Bulletins](./reports/reports.md) +- diff --git a/package-lock.json b/package-lock.json index ffea9acbb0..401f030b4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "@fortawesome/free-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", "@mdx-js/react": "^3.0.1", - "antd": "^5.6.2", + "antd": "^5.22.2", "axios-retry": "^4.5.0", "babel-plugin-macros": "^3.1.0", "clsx": "^1.2.1", @@ -58,7 +58,7 @@ "@typescript-eslint/parser": "^8.2.0", "babel-jest": "^29.6.2", "dotenv": "^16.3.1", - "eslint": "^8.45.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jsx-a11y": "^6.9.0", @@ -499,32 +499,59 @@ } }, "node_modules/@ant-design/colors": { - "version": "7.0.0", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.1.0.tgz", + "integrity": "sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==", "license": "MIT", "dependencies": { - "@ctrl/tinycolor": "^3.4.0" + "@ctrl/tinycolor": "^3.6.1" } }, "node_modules/@ant-design/cssinjs": { - "version": "1.18.1", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.22.0.tgz", + "integrity": "sha512-W9XSFeRPR0mAN3OuxfuS/xhENCYKf+8s+QyNNER0FSWoK9OpISTag6CCweg6lq0hASQ/2Vcza0Z8/kGivCP0Ng==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.11.1", "@emotion/hash": "^0.8.0", "@emotion/unitless": "^0.7.5", "classnames": "^2.3.1", - "csstype": "3.1.2", + "csstype": "^3.1.3", "rc-util": "^5.35.0", - "stylis": "^4.0.13" + "stylis": "^4.3.4" }, "peerDependencies": { "react": ">=16.0.0", "react-dom": ">=16.0.0" } }, - "node_modules/@ant-design/cssinjs/node_modules/csstype": { - "version": "3.1.2", - "license": "MIT" + "node_modules/@ant-design/cssinjs-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.1.tgz", + "integrity": "sha512-2HAiyGGGnM0es40SxdszeQAU5iWp41wBIInq+ONTCKjlSKOrzQfnw4JDtB8IBmqE6tQaEKwmzTP2LGdt5DSwYQ==", + "license": "MIT", + "dependencies": { + "@ant-design/cssinjs": "^1.21.0", + "@babel/runtime": "^7.23.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@ant-design/fast-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz", + "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7" + }, + "engines": { + "node": ">=8.x" + } }, "node_modules/@ant-design/icons": { "version": "5.5.1", @@ -550,7 +577,9 @@ "license": "MIT" }, "node_modules/@ant-design/react-slick": { - "version": "1.0.2", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz", + "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.4", @@ -7296,6 +7325,8 @@ }, "node_modules/@emotion/hash": { "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", "license": "MIT" }, "node_modules/@emotion/memoize": { @@ -7349,6 +7380,8 @@ }, "node_modules/@emotion/unitless": { "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { @@ -9804,14 +9837,28 @@ "version": "1.0.0-next.24", "license": "MIT" }, + "node_modules/@rc-component/async-validator": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", + "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.4" + }, + "engines": { + "node": ">=14.x" + } + }, "node_modules/@rc-component/color-picker": { - "version": "1.4.1", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz", + "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.10.1", - "@ctrl/tinycolor": "^3.6.0", + "@ant-design/fast-color": "^2.0.6", + "@babel/runtime": "^7.23.6", "classnames": "^2.2.6", - "rc-util": "^5.30.0" + "rc-util": "^5.38.1" }, "peerDependencies": { "react": ">=16.9.0", @@ -9820,6 +9867,8 @@ }, "node_modules/@rc-component/context": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", + "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -9832,6 +9881,8 @@ }, "node_modules/@rc-component/mini-decimal": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", + "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.0" @@ -9858,6 +9909,8 @@ }, "node_modules/@rc-component/portal": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", + "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.0", @@ -9872,13 +9925,33 @@ "react-dom": ">=16.9.0" } }, + "node_modules/@rc-component/qrcode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz", + "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@rc-component/tour": { - "version": "1.11.1", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz", + "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.0", "@rc-component/portal": "^1.0.0-9", - "@rc-component/trigger": "^1.3.6", + "@rc-component/trigger": "^2.0.0", "classnames": "^2.3.2", "rc-util": "^5.24.4" }, @@ -9891,7 +9964,9 @@ } }, "node_modules/@rc-component/trigger": { - "version": "1.18.2", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.5.tgz", + "integrity": "sha512-F1EJ4KjFpGAHAjuKvOyZB/6IZDkVx0bHl0M4fQM5wXcmm7lgTgVSSnR3bXwdmS6jOJGHOqfDxIJW3WUvwMIXhQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.2", @@ -13195,57 +13270,60 @@ } }, "node_modules/antd": { - "version": "5.12.2", + "version": "5.22.2", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.22.2.tgz", + "integrity": "sha512-vihhiJbm9VG3d6boUeD1q2MXMax+qBrXhgqCEC+45v8iGUF6m4Ct+lFiCW4oWaN3EABOsbVA6Svy3Rj/QkQFKw==", "license": "MIT", "dependencies": { - "@ant-design/colors": "^7.0.0", - "@ant-design/cssinjs": "^1.18.1", - "@ant-design/icons": "^5.2.6", - "@ant-design/react-slick": "~1.0.2", - "@babel/runtime": "^7.23.4", + "@ant-design/colors": "^7.1.0", + "@ant-design/cssinjs": "^1.21.1", + "@ant-design/cssinjs-utils": "^1.1.1", + "@ant-design/icons": "^5.5.1", + "@ant-design/react-slick": "~1.1.2", + "@babel/runtime": "^7.25.7", "@ctrl/tinycolor": "^3.6.1", - "@rc-component/color-picker": "~1.4.1", + "@rc-component/color-picker": "~2.0.1", "@rc-component/mutate-observer": "^1.1.0", - "@rc-component/tour": "~1.11.1", - "@rc-component/trigger": "^1.18.2", - "classnames": "^2.3.2", + "@rc-component/qrcode": "~1.0.0", + "@rc-component/tour": "~1.15.1", + "@rc-component/trigger": "^2.2.5", + "classnames": "^2.5.1", "copy-to-clipboard": "^3.3.3", - "dayjs": "^1.11.1", - "qrcode.react": "^3.1.0", - "rc-cascader": "~3.20.0", - "rc-checkbox": "~3.1.0", - "rc-collapse": "~3.7.2", - "rc-dialog": "~9.3.4", - "rc-drawer": "~6.5.2", - "rc-dropdown": "~4.1.0", - "rc-field-form": "~1.41.0", - "rc-image": "~7.5.1", - "rc-input": "~1.3.6", - "rc-input-number": "~8.4.0", - "rc-mentions": "~2.9.1", - "rc-menu": "~9.12.4", - "rc-motion": "^2.9.0", - "rc-notification": "~5.3.0", - "rc-pagination": "~4.0.3", - "rc-picker": "~3.14.6", - "rc-progress": "~3.5.1", - "rc-rate": "~2.12.0", + "dayjs": "^1.11.11", + "rc-cascader": "~3.30.0", + "rc-checkbox": "~3.3.0", + "rc-collapse": "~3.9.0", + "rc-dialog": "~9.6.0", + "rc-drawer": "~7.2.0", + "rc-dropdown": "~4.2.0", + "rc-field-form": "~2.5.1", + "rc-image": "~7.11.0", + "rc-input": "~1.6.3", + "rc-input-number": "~9.3.0", + "rc-mentions": "~2.17.0", + "rc-menu": "~9.16.0", + "rc-motion": "^2.9.3", + "rc-notification": "~5.6.2", + "rc-pagination": "~4.3.0", + "rc-picker": "~4.8.1", + "rc-progress": "~4.0.0", + "rc-rate": "~2.13.0", "rc-resize-observer": "^1.4.0", - "rc-segmented": "~2.2.2", - "rc-select": "~14.10.0", - "rc-slider": "~10.5.0", + "rc-segmented": "~2.5.0", + "rc-select": "~14.16.3", + "rc-slider": "~11.1.7", "rc-steps": "~6.0.1", "rc-switch": "~4.1.0", - "rc-table": "~7.36.0", - "rc-tabs": "~12.14.1", - "rc-textarea": "~1.5.3", - "rc-tooltip": "~6.1.2", - "rc-tree": "~5.8.2", - "rc-tree-select": "~5.15.0", - "rc-upload": "~4.3.5", - "rc-util": "^5.38.1", + "rc-table": "~7.48.1", + "rc-tabs": "~15.4.0", + "rc-textarea": "~1.8.2", + "rc-tooltip": "~6.2.1", + "rc-tree": "~5.10.1", + "rc-tree-select": "~5.24.4", + "rc-upload": "~4.8.1", + "rc-util": "^5.43.0", "scroll-into-view-if-needed": "^3.1.0", - "throttle-debounce": "^5.0.0" + "throttle-debounce": "^5.0.2" }, "funding": { "type": "opencollective", @@ -13514,10 +13592,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-tree-filter": { - "version": "2.1.0", - "license": "MIT" - }, "node_modules/array-union": { "version": "2.1.0", "license": "MIT", @@ -13750,10 +13824,6 @@ "node": ">= 0.10" } }, - "node_modules/async-validator": { - "version": "4.2.5", - "license": "MIT" - }, "node_modules/asynckit": { "version": "0.4.0", "dev": true, @@ -15864,7 +15934,9 @@ } }, "node_modules/classnames": { - "version": "2.3.2", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", "license": "MIT" }, "node_modules/clean-css": { @@ -30786,6 +30858,8 @@ }, "node_modules/json2mq": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", "license": "MIT", "dependencies": { "string-convert": "^0.2.0" @@ -59666,13 +59740,6 @@ ], "license": "MIT" }, - "node_modules/qrcode.react": { - "version": "3.1.0", - "license": "ISC", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/qs": { "version": "6.5.3", "dev": true, @@ -59815,15 +59882,16 @@ } }, "node_modules/rc-cascader": { - "version": "3.20.0", + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.30.0.tgz", + "integrity": "sha512-rrzSbk1Bdqbu+pDwiLCLHu72+lwX9BZ28+JKzoi0DWZ4N29QYFeip8Gctl33QVd2Xg3Rf14D3yAOG76ElJw16w==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "array-tree-filter": "^2.1.0", + "@babel/runtime": "^7.25.7", "classnames": "^2.3.1", - "rc-select": "~14.10.0", - "rc-tree": "~5.8.1", - "rc-util": "^5.37.0" + "rc-select": "~14.16.2", + "rc-tree": "~5.10.1", + "rc-util": "^5.43.0" }, "peerDependencies": { "react": ">=16.9.0", @@ -59831,7 +59899,9 @@ } }, "node_modules/rc-checkbox": { - "version": "3.1.0", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz", + "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -59844,7 +59914,9 @@ } }, "node_modules/rc-collapse": { - "version": "3.7.2", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.9.0.tgz", + "integrity": "sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -59858,7 +59930,9 @@ } }, "node_modules/rc-dialog": { - "version": "9.3.4", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz", + "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -59873,14 +59947,16 @@ } }, "node_modules/rc-drawer": { - "version": "6.5.2", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz", + "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.10.1", + "@babel/runtime": "^7.23.9", "@rc-component/portal": "^1.1.1", "classnames": "^2.2.6", "rc-motion": "^2.6.1", - "rc-util": "^5.36.0" + "rc-util": "^5.38.1" }, "peerDependencies": { "react": ">=16.9.0", @@ -59888,11 +59964,13 @@ } }, "node_modules/rc-dropdown": { - "version": "4.1.0", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.0.tgz", + "integrity": "sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", - "@rc-component/trigger": "^1.7.0", + "@rc-component/trigger": "^2.0.0", "classnames": "^2.2.6", "rc-util": "^5.17.0" }, @@ -59902,11 +59980,13 @@ } }, "node_modules/rc-field-form": { - "version": "1.41.0", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.5.1.tgz", + "integrity": "sha512-33hunXwynQJyeae7LS3hMGTXNeRBjiPyPYgB0824EbmLHiXC1EBGyUwRh6xjLRy9c+en5WARYN0gJz5+JAqwig==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.0", - "async-validator": "^4.1.0", + "@rc-component/async-validator": "^5.0.3", "rc-util": "^5.32.2" }, "engines": { @@ -59918,13 +59998,15 @@ } }, "node_modules/rc-image": { - "version": "7.5.1", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.11.0.tgz", + "integrity": "sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.11.2", "@rc-component/portal": "^1.0.2", "classnames": "^2.2.6", - "rc-dialog": "~9.3.4", + "rc-dialog": "~9.6.0", "rc-motion": "^2.6.2", "rc-util": "^5.34.1" }, @@ -59934,7 +60016,9 @@ } }, "node_modules/rc-input": { - "version": "1.3.11", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.6.3.tgz", + "integrity": "sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.11.1", @@ -59947,14 +60031,16 @@ } }, "node_modules/rc-input-number": { - "version": "8.4.0", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.3.0.tgz", + "integrity": "sha512-JQ363ywqRyxwgVxpg2z2kja3CehTpYdqR7emJ/6yJjRdbvo+RvfE83fcpBCIJRq3zLp8SakmEXq60qzWyZ7Usw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", "@rc-component/mini-decimal": "^1.0.1", "classnames": "^2.2.5", - "rc-input": "~1.3.5", - "rc-util": "^5.28.0" + "rc-input": "~1.6.0", + "rc-util": "^5.40.1" }, "peerDependencies": { "react": ">=16.9.0", @@ -59962,15 +60048,17 @@ } }, "node_modules/rc-mentions": { - "version": "2.9.1", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.17.0.tgz", + "integrity": "sha512-sfHy+qLvc+p8jx8GUsujZWXDOIlIimp6YQz7N5ONQ6bHsa2kyG+BLa5k2wuxgebBbH97is33wxiyq5UkiXRpHA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.22.5", - "@rc-component/trigger": "^1.5.0", + "@rc-component/trigger": "^2.0.0", "classnames": "^2.2.6", - "rc-input": "~1.3.5", - "rc-menu": "~9.12.0", - "rc-textarea": "~1.5.0", + "rc-input": "~1.6.0", + "rc-menu": "~9.16.0", + "rc-textarea": "~1.8.0", "rc-util": "^5.34.1" }, "peerDependencies": { @@ -59979,11 +60067,13 @@ } }, "node_modules/rc-menu": { - "version": "9.12.4", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.16.0.tgz", + "integrity": "sha512-vAL0yqPkmXWk3+YKRkmIR8TYj3RVdEt3ptG2jCJXWNAvQbT0VJJdRyHZ7kG/l1JsZlB+VJq/VcYOo69VR4oD+w==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", - "@rc-component/trigger": "^1.17.0", + "@rc-component/trigger": "^2.0.0", "classnames": "2.x", "rc-motion": "^2.4.3", "rc-overflow": "^1.3.1", @@ -59995,12 +60085,14 @@ } }, "node_modules/rc-motion": { - "version": "2.9.0", + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.3.tgz", + "integrity": "sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", - "rc-util": "^5.21.0" + "rc-util": "^5.43.0" }, "peerDependencies": { "react": ">=16.9.0", @@ -60008,7 +60100,9 @@ } }, "node_modules/rc-notification": { - "version": "5.3.0", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.2.tgz", + "integrity": "sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -60026,6 +60120,8 @@ }, "node_modules/rc-overflow": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", + "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.11.1", @@ -60039,7 +60135,9 @@ } }, "node_modules/rc-pagination": { - "version": "4.0.3", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.3.0.tgz", + "integrity": "sha512-UubEWA0ShnroQ1tDa291Fzw6kj0iOeF26IsUObxYTpimgj4/qPCWVFl18RLZE+0Up1IZg0IK4pMn6nB3mjvB7g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -60052,13 +60150,17 @@ } }, "node_modules/rc-picker": { - "version": "3.14.6", + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.8.2.tgz", + "integrity": "sha512-I6Nn4ngkRskSD//rsXDvjlEQ8CzX9kPQrUIb7+qTY49erJaa3/oKJWmi6JIxo/A7gy59phNmPTdhKosAa/NrQQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/trigger": "^1.5.0", + "@babel/runtime": "^7.24.7", + "@rc-component/trigger": "^2.0.0", "classnames": "^2.2.1", - "rc-util": "^5.30.0" + "rc-overflow": "^1.3.2", + "rc-resize-observer": "^1.4.0", + "rc-util": "^5.43.0" }, "engines": { "node": ">=8.x" @@ -60087,7 +60189,9 @@ } }, "node_modules/rc-progress": { - "version": "3.5.1", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz", + "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -60100,7 +60204,9 @@ } }, "node_modules/rc-rate": { - "version": "2.12.0", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", + "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -60117,6 +60223,8 @@ }, "node_modules/rc-resize-observer": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", + "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.7", @@ -60130,7 +60238,9 @@ } }, "node_modules/rc-segmented": { - "version": "2.2.2", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.5.0.tgz", + "integrity": "sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.11.1", @@ -60144,11 +60254,13 @@ } }, "node_modules/rc-select": { - "version": "14.10.0", + "version": "14.16.3", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.16.3.tgz", + "integrity": "sha512-51+j6s3fJJJXB7E+B6W1hM4Tjzv1B/Decooz9ilgegDBt3ZAth1b/xMwYCTrT5BbG2e53XACQsyDib2+3Ro1fg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", - "@rc-component/trigger": "^1.5.0", + "@rc-component/trigger": "^2.1.1", "classnames": "2.x", "rc-motion": "^2.0.1", "rc-overflow": "^1.3.1", @@ -60164,12 +60276,14 @@ } }, "node_modules/rc-slider": { - "version": "10.5.0", + "version": "11.1.7", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.7.tgz", + "integrity": "sha512-ytYbZei81TX7otdC0QvoYD72XSlxvTihNth5OeZ6PMXyEDq/vHdWFulQmfDGyXK1NwKwSlKgpvINOa88uT5g2A==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", - "rc-util": "^5.27.0" + "rc-util": "^5.36.0" }, "engines": { "node": ">=8.x" @@ -60209,15 +60323,17 @@ } }, "node_modules/rc-table": { - "version": "7.36.0", + "version": "7.48.1", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.48.1.tgz", + "integrity": "sha512-Z4mDKjWg+xz/Ezdw6ivWcbqRpaJ0QfCORRoRrlrw65KSGZLK8OcTdacH22/fyGb8L4It/0/9qcMm8VrVAk/WBw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", "@rc-component/context": "^1.4.0", "classnames": "^2.2.5", "rc-resize-observer": "^1.1.0", - "rc-util": "^5.37.0", - "rc-virtual-list": "^3.11.1" + "rc-util": "^5.41.0", + "rc-virtual-list": "^3.14.2" }, "engines": { "node": ">=8.x" @@ -60228,13 +60344,15 @@ } }, "node_modules/rc-tabs": { - "version": "12.14.1", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.4.0.tgz", + "integrity": "sha512-llKuyiAVqmXm2z7OrmhX5cNb2ueZaL8ZyA2P4R+6/72NYYcbEgOXibwHiQCFY2RiN3swXl53SIABi2CumUS02g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.11.2", "classnames": "2.x", - "rc-dropdown": "~4.1.0", - "rc-menu": "~9.12.0", + "rc-dropdown": "~4.2.0", + "rc-menu": "~9.16.0", "rc-motion": "^2.6.2", "rc-resize-observer": "^1.0.0", "rc-util": "^5.34.1" @@ -60248,12 +60366,14 @@ } }, "node_modules/rc-textarea": { - "version": "1.5.3", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.8.2.tgz", + "integrity": "sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", - "rc-input": "~1.3.5", + "rc-input": "~1.6.0", "rc-resize-observer": "^1.0.0", "rc-util": "^5.27.0" }, @@ -60263,11 +60383,13 @@ } }, "node_modules/rc-tooltip": { - "version": "6.1.2", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.1.tgz", + "integrity": "sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.11.2", - "@rc-component/trigger": "^1.18.0", + "@rc-component/trigger": "^2.0.0", "classnames": "^2.3.1" }, "peerDependencies": { @@ -60276,7 +60398,9 @@ } }, "node_modules/rc-tree": { - "version": "5.8.2", + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.10.1.tgz", + "integrity": "sha512-FPXb3tT/u39mgjr6JNlHaUTYfHkVGW56XaGDahDpEFLGsnPxGcVLNTjcqoQb/GNbSCycl7tD7EvIymwOTP0+Yw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", @@ -60294,14 +60418,16 @@ } }, "node_modules/rc-tree-select": { - "version": "5.15.0", + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.24.5.tgz", + "integrity": "sha512-PnyR8LZJWaiEFw0SHRqo4MNQWyyZsyMs8eNmo68uXZWjxc7QqeWcjPPoONN0rc90c3HZqGF9z+Roz+GLzY5GXA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.10.1", + "@babel/runtime": "^7.25.7", "classnames": "2.x", - "rc-select": "~14.10.0", - "rc-tree": "~5.8.1", - "rc-util": "^5.16.1" + "rc-select": "~14.16.2", + "rc-tree": "~5.10.1", + "rc-util": "^5.43.0" }, "peerDependencies": { "react": "*", @@ -60309,7 +60435,9 @@ } }, "node_modules/rc-upload": { - "version": "4.3.5", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.8.1.tgz", + "integrity": "sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", @@ -60322,7 +60450,9 @@ } }, "node_modules/rc-util": { - "version": "5.38.1", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.43.0.tgz", + "integrity": "sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", @@ -60338,7 +60468,9 @@ "license": "MIT" }, "node_modules/rc-virtual-list": { - "version": "3.11.3", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.15.0.tgz", + "integrity": "sha512-dF2YQztqrU3ijAeWOqscTshCEr7vpimzSqAVjO1AyAmaqcHulaXpnGR0ptK5PXfxTUy48VkJOiglMIxlkYGs0w==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.0", @@ -60350,8 +60482,8 @@ "node": ">=8.x" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, "node_modules/rc/node_modules/strip-json-comments": { @@ -61802,6 +61934,8 @@ }, "node_modules/resize-observer-polyfill": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", "license": "MIT" }, "node_modules/resolve": { @@ -63976,6 +64110,8 @@ }, "node_modules/string-convert": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==", "license": "MIT" }, "node_modules/string-length": { @@ -64340,7 +64476,9 @@ } }, "node_modules/stylis": { - "version": "4.3.0", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", "license": "MIT" }, "node_modules/stylus": { @@ -65329,7 +65467,9 @@ } }, "node_modules/throttle-debounce": { - "version": "5.0.0", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", + "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", "license": "MIT", "engines": { "node": ">=12.22" diff --git a/package.json b/package.json index b59ea1f4c5..792c3f6c19 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start --host 0.0.0.0 --port 9000", - "build": "npm run generate-api-docs && npm run generate-partials && docusaurus build", + "build": "npm run generate-api-docs && npm run cves && npm run generate-partials && docusaurus build", "swizzle": "docusaurus swizzle", + "cves": "node utils/cves/index.js", "deploy": "docusaurus deploy", "clear": "docusaurus clear", "serve": "docusaurus serve", @@ -19,7 +20,7 @@ "clean-api-docs": "docusaurus clean-api-docs palette", "run-api-parser": "node utils/api-parser/index.js", "generate-partials": "./scripts/generate-partials.sh", - "lint": "eslint . --ext .js,.ts,.jsx,.tsx", + "lint": "eslint . -c .eslintrc.js --ext .js,.ts,.jsx,.tsx", "lint:fix": "npm run lint -- --fix", "format": "prettier --write \"**/*.{js,jsx,json,ts,tsx,md,mdx,css}\"", "format-check": "prettier . --check" @@ -47,7 +48,7 @@ "@fortawesome/free-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", "@mdx-js/react": "^3.0.1", - "antd": "^5.6.2", + "antd": "^5.22.2", "axios-retry": "^4.5.0", "babel-plugin-macros": "^3.1.0", "clsx": "^1.2.1", @@ -84,7 +85,7 @@ "@typescript-eslint/parser": "^8.2.0", "babel-jest": "^29.6.2", "dotenv": "^16.3.1", - "eslint": "^8.45.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jsx-a11y": "^6.9.0", diff --git a/redirects.js b/redirects.js index b7d15534ce..4f9465ac51 100644 --- a/redirects.js +++ b/redirects.js @@ -541,6 +541,91 @@ let redirects = [ from: "/user-management/project-association/", to: "/user-management/palette-rbac/assign-a-role/", }, + { + from: [ + "/security-bulletins/reports/cve-2005-2541", + "/security-bulletins/reports/cve-2012-2663", + "/security-bulletins/reports/cve-2015-20107", + "/security-bulletins/reports/cve-2015-8855", + "/security-bulletins/reports/cve-2016-1585", + "/security-bulletins/reports/cve-2016-20013", + "/security-bulletins/reports/cve-2017-11164", + "/security-bulletins/reports/cve-2018-20225", + "/security-bulletins/reports/cve-2018-20657", + "/security-bulletins/reports/cve-2018-20796", + "/security-bulletins/reports/cve-2018-20839", + "/security-bulletins/reports/cve-2019-1010022", + "/security-bulletins/reports/cve-2019-12900", + "/security-bulletins/reports/cve-2019-17543", + "/security-bulletins/reports/cve-2019-19244", + "/security-bulletins/reports/cve-2019-9192", + "/security-bulletins/reports/cve-2019-9674", + "/security-bulletins/reports/cve-2019-9923", + "/security-bulletins/reports/cve-2019-9936", + "/security-bulletins/reports/cve-2019-9937", + "/security-bulletins/reports/cve-2020-35512", + "/security-bulletins/reports/cve-2020-36325", + "/security-bulletins/reports/cve-2021-3737", + "/security-bulletins/reports/cve-2021-39537", + "/security-bulletins/reports/cve-2021-42694", + "/security-bulletins/reports/cve-2021-46848", + "/security-bulletins/reports/cve-2022-0391", + "/security-bulletins/reports/cve-2022-23990", + "/security-bulletins/reports/cve-2022-25883", + "/security-bulletins/reports/cve-2022-28357", + "/security-bulletins/reports/cve-2022-28948", + "/security-bulletins/reports/cve-2022-41409", + "/security-bulletins/reports/cve-2022-41723", + "/security-bulletins/reports/cve-2022-41724", + "/security-bulletins/reports/cve-2022-41725", + "/security-bulletins/reports/cve-2022-45061", + "/security-bulletins/reports/cve-2022-48560", + "/security-bulletins/reports/cve-2022-48565", + "/security-bulletins/reports/cve-2022-4899", + "/security-bulletins/reports/cve-2023-0464", + "/security-bulletins/reports/cve-2023-24329", + "/security-bulletins/reports/cve-2023-24534", + "/security-bulletins/reports/cve-2023-24536", + "/security-bulletins/reports/cve-2023-24537", + "/security-bulletins/reports/cve-2023-24538", + "/security-bulletins/reports/cve-2023-24539", + "/security-bulletins/reports/cve-2023-24540", + "/security-bulletins/reports/cve-2023-26604", + "/security-bulletins/reports/cve-2023-27534", + "/security-bulletins/reports/cve-2023-29400", + "/security-bulletins/reports/cve-2023-29403", + "/security-bulletins/reports/cve-2023-29499", + "/security-bulletins/reports/cve-2023-32636", + "/security-bulletins/reports/cve-2023-37920", + "/security-bulletins/reports/cve-2023-39325", + "/security-bulletins/reports/cve-2023-4156", + "/security-bulletins/reports/cve-2023-44487", + "/security-bulletins/reports/cve-2023-45142", + "/security-bulletins/reports/cve-2023-45287", + "/security-bulletins/reports/cve-2023-47108", + "/security-bulletins/reports/cve-2023-49569", + "/security-bulletins/reports/cve-2023-52356", + "/security-bulletins/reports/cve-2024-0743", + "/security-bulletins/reports/cve-2024-0760", + "/security-bulletins/reports/cve-2024-1737", + "/security-bulletins/reports/cve-2024-1975", + "/security-bulletins/reports/cve-2024-21626", + "/security-bulletins/reports/cve-2024-24790", + "/security-bulletins/reports/cve-2024-32002", + "/security-bulletins/reports/cve-2024-35325", + "/security-bulletins/reports/cve-2024-3651", + "/security-bulletins/reports/cve-2024-37370", + "/security-bulletins/reports/cve-2024-37371", + "/security-bulletins/reports/cve-2024-38428", + "/security-bulletins/reports/cve-2024-45490", + "/security-bulletins/reports/cve-2024-45491", + "/security-bulletins/reports/cve-2024-45492", + "/security-bulletins/reports/cve-2024-6197", + "/security-bulletins/reports/cve-2024-6232", + "/security-bulletins/reports/cve-2024-7592", + ], + to: "/security-bulletins/reports/", + }, ]; if (packRedirects.length > 0) { diff --git a/src/components/CveReportsTable/CveReportTable.module.scss b/src/components/CveReportsTable/CveReportTable.module.scss new file mode 100644 index 0000000000..c83c25192c --- /dev/null +++ b/src/components/CveReportsTable/CveReportTable.module.scss @@ -0,0 +1,35 @@ +.wrapper { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .tabPane { + padding-top: 15px; + font-size: 16px; + width: 100%; + // Karl's workaround for reducing the jank issue where the tabs disappear when refreshing the page. + // The spinner is displayed while the page is loading, and the entire table is hidden until the page is fully loaded. + min-height: 300px; + } +} + +.tableContainer { + display: block; + + @media (max-width: 768px) { + display: none; + } +} + +.unsupportedMessage { + display: none; + + @media (max-width: 768px) { + display: block; + text-align: center; + padding: 20px; + font-size: 1.2em; + color: #555; + } +} diff --git a/src/components/CveReportsTable/CveReportsTable.tsx b/src/components/CveReportsTable/CveReportsTable.tsx new file mode 100644 index 0000000000..324a92a862 --- /dev/null +++ b/src/components/CveReportsTable/CveReportsTable.tsx @@ -0,0 +1,273 @@ +import React, { useState, useEffect, useMemo } from "react"; +import { Tabs, ConfigProvider, Table, theme, Spin } from "antd"; +import { useColorMode } from "@docusaurus/theme-common"; +import useIsBrowser from "@docusaurus/useIsBrowser"; +import Link from "@docusaurus/Link"; +import type { ColumnsType } from "antd/es/table"; +import Admonition from "@theme/Admonition"; +import styles from "./CveReportTable.module.scss"; +import semver from "semver"; + +interface CveData { + palette: Cve[]; + paletteAirgap: Cve[]; + vertex: Cve[]; + vertexAirgap: Cve[]; +} + +interface Cve { + metadata: { + uid: string; + cve: string; + summary: string; + cvssScore: number; + nistSeverity: string; + trivySeverity: string; + grypeSeverity: string; + cvePublishedTimestamp: string; + cveLastModifiedTimestamp: string; + advCreatedTimestamp: string; + advLastModifiedTimestamp: string; + }; + spec: { + assessment: { + thirdParty: { + isDependentOnThirdParty: boolean; + }; + }; + impact: { + impactedVersions: string[]; + }; + }; + status: { + status: string; + }; +} + +interface MinimizedCve { + metadata: { + uid: string; + cve: string; + cvssScore: number; + cvePublishedTimestamp: string; + cveLastModifiedTimestamp: string; + }; + spec: { + assessment: { + thirdParty: { + isDependentOnThirdParty: boolean; + }; + }; + impact: { + impactedVersions: string[]; + }; + }; + status: { + status: string; + }; +} + +type CveDataUnion = + | CveData + | { + palette: MinimizedCve[]; + paletteAirgap: MinimizedCve[]; + vertex: MinimizedCve[]; + vertexAirgap: MinimizedCve[]; + }; + +export default function CveReportsTable() { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const isBrowser = useIsBrowser(); + const [activeTabKey, setActiveTabKey] = useState("palette"); + const { colorMode } = useColorMode(); + const { defaultAlgorithm, darkAlgorithm } = theme; + + useEffect(() => { + if (isBrowser) { + const hash = window.location.hash?.replace("#", "") || "palette"; + setActiveTabKey(hash); + } + }, [isBrowser]); + + useEffect(() => { + const minimizeData = (entry: Cve): MinimizedCve => ({ + metadata: { + uid: entry.metadata.uid, + cve: entry.metadata.cve, + cvssScore: entry.metadata.cvssScore, + cvePublishedTimestamp: entry.metadata.cvePublishedTimestamp, + cveLastModifiedTimestamp: entry.metadata.cveLastModifiedTimestamp, + }, + spec: { + assessment: { + thirdParty: { isDependentOnThirdParty: entry.spec.assessment.thirdParty.isDependentOnThirdParty }, + }, + impact: { impactedVersions: entry.spec.impact.impactedVersions }, + }, + status: { status: entry.status.status }, + }); + + const loadData = async () => { + try { + const response = (await import("../../../.docusaurus/security-bulletins/default/data.json")).default; // eslint-disable-line @typescript-eslint/no-unsafe-member-access + const responseData = response as CveData; + + const reducedData: CveDataUnion = { + palette: responseData.palette.map(minimizeData), + paletteAirgap: responseData.paletteAirgap.map(minimizeData), + vertex: responseData.vertex.map(minimizeData), + vertexAirgap: responseData.vertexAirgap.map(minimizeData), + }; + setData(reducedData); + } catch (error) { + console.error("Error loading data:", error); + } finally { + setLoading(false); + } + }; + + loadData().catch((error) => console.error("Error loading data:", error)); + }, []); + + useEffect(() => { + if (isBrowser) { + window.location.hash = activeTabKey; + } + }, [activeTabKey, isBrowser]); + + const columns: ColumnsType = useMemo( + () => [ + { + title: "CVE ID", + dataIndex: ["metadata", "cve"], + key: "cve", + sorter: (a, b) => a.metadata.cve.localeCompare(b.metadata.cve), + render: (cve: string, record) => ( + + {cve} + + ), + }, + { + title: "Initial Pub Date", + dataIndex: ["metadata", "cvePublishedTimestamp"], + key: "publishedDateTime", + sorter: (a, b) => + new Date(a.metadata.cvePublishedTimestamp).getTime() - new Date(b.metadata.cvePublishedTimestamp).getTime(), + render: (text: string) => new Date(text).toLocaleDateString(), + }, + { + title: "Modified Date", + dataIndex: ["metadata", "cveLastModifiedTimestamp"], + key: "modifiedDateTime", + sorter: (a, b) => + new Date(a.metadata.cveLastModifiedTimestamp).getTime() - + new Date(b.metadata.cveLastModifiedTimestamp).getTime(), + render: (text: string) => new Date(text).toLocaleDateString(), + defaultSortOrder: "descend", + }, + { + title: "Product Version", + dataIndex: ["spec", "impact", "impactedVersions"], + key: "productVersion", + sorter: (a, b) => { + const versionsA = a.spec.impact.impactedVersions.sort(semver.compare).reverse(); + const versionsB = b.spec.impact.impactedVersions.sort(semver.compare).reverse(); + return semver.compare(versionsB[0] || "0.0.0", versionsA[0] || "0.0.0"); + }, + render: (impactedVersions: string[]) => { + const sortedVersions = impactedVersions.sort(semver.compare).reverse().slice(0, 3); + return sortedVersions.join(", ") + (impactedVersions.length > 3 ? ", ..." : ""); + }, + }, + { + title: "Third Party Vulnerability", + dataIndex: ["spec", "assessment", "thirdParty", "isDependentOnThirdParty"], + key: "vulnerabilityType", + sorter: (a, b) => + a.spec.assessment.thirdParty.isDependentOnThirdParty === b.spec.assessment.thirdParty.isDependentOnThirdParty + ? 0 + : 1, + render: (record) => (record ? "Yes" : "No"), + }, + { + title: "CVSS Severity", + dataIndex: ["metadata", "cvssScore"], + key: "baseScore", + sorter: (a, b) => a.metadata.cvssScore - b.metadata.cvssScore, + render: (baseScore: number, record) => ( + {baseScore} + ), + }, + { + title: "Status", + key: "status", + sorter: (a, b) => a.status.status.localeCompare(b.status.status), + render: (record: MinimizedCve) => { + const status = record.status.status; + return status === "Open" || status === "Ongoing" ? 🔍 {status} : ✅ {status}; + }, + }, + ], + [] + ); + + const renderCveTable = (cveList: MinimizedCve[]) => ( +
+ record.metadata.uid} + pagination={{ + pageSizeOptions: ["25", "50", "100", "500", "1000"], + defaultPageSize: 100, + showSizeChanger: true, + }} + scroll={{ y: 800 }} + bordered={true} + tableLayout="fixed" + sticky={true} + /> + + ); + + const tabs = useMemo( + () => [ + { label: "Palette Enterprise", key: "palette", children: renderCveTable(data?.palette || []) }, + { label: "Palette Enterprise Airgap", key: "paletteAirgap", children: renderCveTable(data?.paletteAirgap || []) }, + { label: "VerteX", key: "vertex", children: renderCveTable(data?.vertex || []) }, + { label: "VerteX Airgap", key: "vertexAirgap", children: renderCveTable(data?.vertexAirgap || []) }, + ], + [data] + ); + + if (loading) { + return ( + + ); + } + + return ( +
+ +
+ + The current screen size is not supported. Use a larger display to access the CVE table. + +
+
+ setActiveTabKey(key)} + items={tabs} + destroyInactiveTabPane={false} + type="card" + /> +
+
+
+ ); +} diff --git a/src/components/CveReportsTable/index.ts b/src/components/CveReportsTable/index.ts new file mode 100644 index 0000000000..0cfd2630e3 --- /dev/null +++ b/src/components/CveReportsTable/index.ts @@ -0,0 +1,3 @@ +import CveReportsTable from "./CveReportsTable"; + +export default CveReportsTable; diff --git a/utils/cves/index.js b/utils/cves/index.js new file mode 100644 index 0000000000..43d6b10281 --- /dev/null +++ b/utils/cves/index.js @@ -0,0 +1,283 @@ +const { api, callRateLimitAPI } = require("./requests"); +const { existsSync, mkdirSync } = require("node:fs"); +const { logger } = require("@docusaurus/logger"); +const fs = require("fs").promises; +const path = require("path"); +const { formatDateCveDetails } = require("../helpers/date"); +const { escapeMDXSpecialChars } = require("../helpers/string"); +const { generateMarkdownTable } = require("../helpers/affected-table"); +const { generateRevisionHistory } = require("../helpers/revision-history"); + +async function getSecurityBulletins(payload) { + try { + return await callRateLimitAPI(() => api.post(`https://dso.teams.spectrocloud.com/v1/advisories`, payload)); + } catch (error) { + logger.error(error); + logger.error("Error:", error.response ? error.response.data || error.response.status : error.message); + } +} + +async function generateCVEs() { + let GlobalCVEData = {}; + + const securityBulletins = new Map(); + const dirname = path.join(".docusaurus", "security-bulletins", "default"); + const filename = path.join(dirname, "data.json"); + + if (process.env.DISABLE_SECURITY_INTEGRATIONS === "true") { + logger.info("Security integrations are disabled. Skipping generation of security bulletins."); + if (!existsSync(dirname) || !existsSync(filename)) { + // Write the security bulletins data to a JSON file + mkdirSync(dirname, { recursive: true }); + await fs.writeFile(filename, JSON.stringify({}, null, 2)); + } + return; + } + + if (existsSync(dirname) && existsSync(filename)) { + logger.info("Security bulletins JSON file already exists. Skipping fetching."); + GlobalCVEData = JSON.parse(await fs.readFile(filename, "utf-8")); + } else { + logger.info("Fetching security bulletins..."); + + try { + const palette = await getSecurityBulletins({ + filters: [ + { + field: "metadata.nistSeverity", + operator: "in", + options: ["CRITICAL", "HIGH"], + }, + { + field: "spec.impact.impactedProducts.palette", + operator: "ex", + }, + { + field: "spec.impact.impactedDeployments.connected", + operator: "ex", + }, + ], + }); + const paletteAirgap = await getSecurityBulletins({ + filters: [ + { + field: "metadata.nistSeverity", + operator: "in", + options: ["CRITICAL", "HIGH"], + }, + { + field: "spec.impact.impactedProducts.palette", + operator: "ex", + }, + { + field: "spec.impact.impactedDeployments.airgap", + operator: "ex", + }, + ], + }); + const vertex = await getSecurityBulletins({ + filters: [ + { + field: "metadata.nistSeverity", + operator: "in", + options: ["CRITICAL", "HIGH"], + }, + { + field: "spec.impact.impactedProducts.vertex", + operator: "ex", + }, + { + field: "spec.impact.impactedDeployments.connected", + operator: "ex", + }, + ], + }); + const vertexAirgap = await getSecurityBulletins({ + filters: [ + { + field: "metadata.nistSeverity", + operator: "in", + options: ["CRITICAL", "HIGH"], + }, + { + field: "spec.impact.impactedProducts.vertex", + operator: "ex", + }, + { + field: "spec.impact.impactedDeployments.airgap", + operator: "ex", + }, + ], + }); + + securityBulletins.set("palette", palette); + securityBulletins.set("paletteAirgap", paletteAirgap); + securityBulletins.set("vertex", vertex); + securityBulletins.set("vertexAirgap", vertexAirgap); + + // const plainObject = Object.fromEntries(securityBulletins); + const plainObject = Object.fromEntries( + Array.from(securityBulletins.entries()).map(([key, value]) => [key, value.data]) + ); + GlobalCVEData = plainObject; + + // Write the security bulletins data to a JSON file + mkdirSync(dirname, { recursive: true }); + await fs.writeFile(filename, JSON.stringify(GlobalCVEData, null, 2)); + + logger.info("Finished fetching security bulletins data."); + } catch (error) { + logger.error(error); + logger.error("Error:", error.response ? error.response.status : error.message); + } + } + + await generateMarkdownForCVEs(GlobalCVEData); +} + +async function generateMarkdownForCVEs(GlobalCVEData) { + const allCVEs = Object.values(GlobalCVEData).reduce((acc, curr) => acc.concat(curr), []); + + // To generate the Impact Product & Versions table we need to track all the instances of the same CVE + // The following hashmap will store the data for each CVE and aggregate the impact data for each product + const cveImpactMap = {}; + + for (const item of allCVEs) { + // Let's add the CVE to the map if it doesn't exist + // We can take all of the values from the first instance of the CVE + // Future instances will update the values if they are true + if (!cveImpactMap[item.metadata.cve]) { + cveImpactMap[item.metadata.cve] = { + versions: item.spec.impact.impactedVersions, + impactsPaletteEnterprise: item.spec.impact.impactedProducts.palette, + impactsPaletteEnterpriseAirgap: item.spec.impact.impactedDeployments.airgap, + impactsVerteX: item.spec.impact.impactedProducts.vertex, + impactsVerteXAirgap: item.spec.impact.impactedDeployments.airgap, + }; + } + + // If the CVE already exists in the map, we need to update the values + // But only if the value is true. If the value is false, we don't need to update it. + if (cveImpactMap[item.metadata.cve]) { + cveImpactMap[item.metadata.cve].versions = [ + ...cveImpactMap[item.metadata.cve].versions, + ...item.spec.impact.impactedVersions, + ]; + + if (item.spec.impact.impactedProducts.palette) { + cveImpactMap[item.metadata.cve].impactsPaletteEnterprise = true; + } + + if (item.spec.impact.impactedDeployments.airgap) { + cveImpactMap[item.metadata.cve].impactsPaletteEnterpriseAirgap = true; + } + + if (item.spec.impact.impactedProducts.vertex) { + cveImpactMap[item.metadata.cve].impactsVerteX = true; + } + + if (item.spec.impact.impactedDeployments.airgap) { + cveImpactMap[item.metadata.cve].impactsVerteXAirgap = true; + } + } + } + + const markdownPromises = allCVEs.map((item) => + createCveMarkdown(item, cveImpactMap[item.metadata.cve], "docs/docs-content/security-bulletins/reports/") + ); + + const results = await Promise.all(markdownPromises); + + const failedFiles = results.filter((result) => !result.success); + + if (failedFiles.length > 0) { + logger.error("Failed to generate the following markdown files:"); + failedFiles.forEach((failure) => { + logger.error(`File: ${failure.file}, Error: ${failure.error.message}`); + }); + } + + logger.success("All security bulletin markdown files generated."); +} + +function createCveMarkdown(item, cveImpactData, location) { + const upperCaseCve = item.metadata.cve.toUpperCase(); + const revisions = item.spec.revision; + const uid = item.metadata.uid.toLowerCase(); + + // Generate a table of impacted products + let table = generateMarkdownTable(cveImpactData); + let revisionHistory = generateRevisionHistory(revisions); + + const content = `--- +sidebar_label: "${upperCaseCve}" +title: "${upperCaseCve}" +description: "Lifecycle of ${upperCaseCve}" +sidebar_class_name: "hide-from-sidebar" +hide_table_of_contents: false +toc_max_heading_level: 2 +tags: ["security", "cve"] +--- + +## CVE Details + +[${upperCaseCve}](https://nvd.nist.gov/vuln/detail/${upperCaseCve}) + +## Initial Publication + +${formatDateCveDetails(item.metadata.advCreatedTimestamp)} + +## Last Update + +${formatDateCveDetails(item.metadata.advLastModifiedTimestamp)} + +${item.spec.assessment?.thirdParty?.dependentPackage != "" ? `## Third Party Dependency \n\n${item.spec.assessment.thirdParty.dependentPackage}` : "This CVE does not have a third party dependency."} + + +## NIST CVE Summary + +${escapeMDXSpecialChars(item.metadata.summary)} + +## CVE Severity + +${item.metadata.cvssScore} + +## Our Official Summary + +${item.spec.assessment.justification ? escapeMDXSpecialChars(item.spec.assessment.justification) : "Investigation is ongoing to determine how this vulnerability affects our products."} + +## Status + +${item.status.status} + +## Affected Products & Versions + +${item.spec.impact.isImpacting ? table : "This CVE is non-impacting as the impacting symbol and/or function is not used in the product"} + + +## Revision History + +${revisionHistory ? revisionHistory : "No revision history available."} +`; + + const filePath = path.join(location, `${uid}.md`); + + // Return a promise and include the CVE or file path in the error log + return fs + .writeFile(filePath, content) + .then(() => ({ + success: true, + file: filePath, + })) + .catch((err) => { + console.error(`Error writing file for ${upperCaseCve} at ${filePath}:`, err); + return { + success: false, + file: filePath, + error: err, + }; + }); +} + +// Call the main function to generate CVEs +generateCVEs(); diff --git a/utils/cves/requests.js b/utils/cves/requests.js new file mode 100644 index 0000000000..1d240728ef --- /dev/null +++ b/utils/cves/requests.js @@ -0,0 +1,52 @@ +const axios = require("axios"); +const axiosRetry = require("axios-retry").default; +const { pRateLimit } = require("p-ratelimit"); +require("dotenv").config(); + +const SECURITY_BULLETIN_URL = "https://dso.teams.spectrocloud.com"; + +// Ensure that the authentication token is available in the environment +const authToken = process.env.DSO_AUTH_TOKEN; +if (!authToken) { + throw new Error("DSO_AUTH_TOKEN must be set in the environment to use this plugin."); +} + +const api = axios.create({ + baseURL: SECURITY_BULLETIN_URL, + timeout: 120000, // 2 minutes timeout + headers: { + "Content-Type": "application/json", + Authorization: "Basic " + authToken, // Use the environment variable for auth token + }, +}); + +// Set up rate limiting using pRateLimit +const limit = pRateLimit({ + interval: 2000, // 2 seconds + rate: 10, // 10 API calls per interval + concurrency: 1, // no more than 1 running at once +}); + +axiosRetry(api, { + retries: 3, // Retry up to 3 times + retryDelay: axiosRetry.exponentialDelay, // Exponential backoff starting with 1 second + retryCondition(error) { + // Retry based on status codes + switch (error.response?.status) { + case 500: + case 404: + case 501: + case 429: + return true; + default: + return false; + } + }, +}); + +// Function to handle API calls with rate limiting +function callRateLimitAPI(delayedApiCall) { + return limit(delayedApiCall); +} + +module.exports = { api, callRateLimitAPI }; diff --git a/utils/helpers/affected-table.js b/utils/helpers/affected-table.js new file mode 100644 index 0000000000..da23a3d27b --- /dev/null +++ b/utils/helpers/affected-table.js @@ -0,0 +1,48 @@ +const semver = require("semver"); + +function generateMarkdownTable(cveImpactMap) { + if (!cveImpactMap || typeof cveImpactMap !== "object") { + throw new Error("Invalid input: cveImpactMap must be an object."); + } + + const impactData = { + "Palette Enterprise": cveImpactMap.impactsPaletteEnterprise, + "Palette Enterprise Airgap": cveImpactMap.impactsPaletteEnterpriseAirgap, + VerteX: cveImpactMap.impactsVerteX, + "VerteX Airgap": cveImpactMap.impactsVerteXAirgap, + }; + + const allProductsFalse = Object.values(impactData).every((value) => value === false); + if (allProductsFalse) { + return "Investigation is ongoing to determine how this vulnerability affects our products"; + } + + const anyProductTrue = Object.values(impactData).some((value) => value === true); + if (anyProductTrue && (!cveImpactMap.versions || cveImpactMap.versions.length === 0)) { + throw new Error("Error: Data inconsistency - Products impacted but no versions provided."); + } + + // Create the header row with the specified order + const header = `| Version | Palette Enterprise | Palette Enterprise Airgap | VerteX | VerteX Airgap |\n`; + const separator = `| - | -------- | -------- | -------- | -------- |\n`; + + // const uniqueVersions = Array.from(new Set(cveImpactMap.versions)).sort((a, b) => b.localeCompare(a)); + const uniqueVersions = Array.from(new Set(cveImpactMap.versions)).sort(semver.rcompare); + + const rows = uniqueVersions + .map((version) => { + const row = [ + `| ${version}`, + impactData["Palette Enterprise"] ? "Impacted" : "No Impact", + impactData["Palette Enterprise Airgap"] ? "Impacted" : "No Impact", + impactData["VerteX"] ? "Impacted" : "No Impact", + impactData["VerteX Airgap"] ? "Impacted" : "No Impact", + ].join(" | "); + return row + " |"; + }) + .join("\n"); + + return header + separator + rows; +} + +module.exports = { generateMarkdownTable }; diff --git a/utils/helpers/affected-table.test.js b/utils/helpers/affected-table.test.js new file mode 100644 index 0000000000..5cda941769 --- /dev/null +++ b/utils/helpers/affected-table.test.js @@ -0,0 +1,47 @@ +const { generateMarkdownTable } = require("./affected-table"); + +describe("generateMarkdownTable", () => { + it("should generate a markdown table for two products with mixed impact", () => { + const cveImpactMap = { + versions: ["4.4.20", "4.5.3"], + impactsPaletteEnterprise: true, + impactsPaletteEnterpriseAirgap: false, + impactsVerteX: false, + impactsVerteXAirgap: false, + }; + + const expectedTable = `| Version | Palette Enterprise | Palette Enterprise Airgap | VerteX | VerteX Airgap | +|-|--------|--------|--------|--------| +| 4.5.3 | Impacted | No Impact | No Impact | No Impact | +| 4.4.20 | Impacted | No Impact | No Impact | No Impact |`; + + expect(generateMarkdownTable(cveImpactMap).replace(/\s+/g, "")).toBe(expectedTable.replace(/\s+/g, "")); + }); + + it("should return investigation message when all products are not impacted", () => { + const cveImpactMap = { + versions: ["4.4.20", "4.5.3"], + impactsPaletteEnterprise: false, + impactsPaletteEnterpriseAirgap: false, + impactsVerteX: false, + impactsVerteXAirgap: false, + }; + + const expectedMessage = "Investigation is ongoing to determine how this vulnerability affects our products"; + expect(generateMarkdownTable(cveImpactMap)).toBe(expectedMessage); + }); + + it("should throw an error when products are impacted but no versions are provided", () => { + const cveImpactMap = { + versions: [], + impactsPaletteEnterprise: true, + impactsPaletteEnterpriseAirgap: false, + impactsVerteX: false, + impactsVerteXAirgap: false, + }; + + expect(() => generateMarkdownTable(cveImpactMap)).toThrow( + "Error: Data inconsistency - Products impacted but no versions provided." + ); + }); +}); diff --git a/utils/helpers/date.js b/utils/helpers/date.js new file mode 100644 index 0000000000..d49b8dcb84 --- /dev/null +++ b/utils/helpers/date.js @@ -0,0 +1,23 @@ +function getTodayFormattedDate() { + const options = { timeZone: "America/Los_Angeles", year: "numeric", month: "2-digit", day: "2-digit" }; + const formattedDate = new Date().toLocaleDateString("en-CA", options); + return formattedDate; +} + +function formatDateCveDetails(isoString) { + const date = new Date(isoString); + + // Check if the date is valid + if (isNaN(date.getTime())) { + console.warn(`Invalid date string: ${isoString}`); + return "N/A"; // or an appropriate placeholder for invalid dates + } + + const month = String(date.getUTCMonth() + 1).padStart(2, "0"); // Pad month to 2 digits + const day = String(date.getUTCDate()).padStart(2, "0"); // Pad day to 2 digits + const year = date.getUTCFullYear(); + + return `${month}/${day}/${year}`; +} + +module.exports = { getTodayFormattedDate, formatDateCveDetails }; diff --git a/utils/helpers/dates.test.js b/utils/helpers/dates.test.js new file mode 100644 index 0000000000..d06e062284 --- /dev/null +++ b/utils/helpers/dates.test.js @@ -0,0 +1,51 @@ +const { getTodayFormattedDate, formatDateCveDetails } = require("./date"); + +describe("getTodayFormattedDate", () => { + it("should return today's date formatted as YYYY-MM-DD in America/Los_Angeles timezone", () => { + const options = { timeZone: "America/Los_Angeles", year: "numeric", month: "2-digit", day: "2-digit" }; + const expectedDate = new Date().toLocaleDateString("en-CA", options); + + expect(getTodayFormattedDate()).toBe(expectedDate); + }); + + it("should return the date in YYYY-MM-DD format", () => { + const formattedDate = getTodayFormattedDate(); + expect(formattedDate).toMatch(/^\d{4}-\d{2}-\d{2}$/); // Check for correct format + }); +}); + +describe("formatDateCveDetails", () => { + it("should format ISO string date to MM/DD/YYYY with zero-padded month and day", () => { + const isoString = "2023-09-05T00:00:00Z"; + const formattedDate = formatDateCveDetails(isoString); + + expect(formattedDate).toBe("09/05/2023"); + }); + + it("should handle leap years correctly", () => { + const isoString = "2024-02-29T00:00:00Z"; + const formattedDate = formatDateCveDetails(isoString); + + expect(formattedDate).toBe("02/29/2024"); + }); + + it("should return the correct date even with different time zones in the input", () => { + const isoString = "2023-09-20T15:00:00Z"; // Time zone is UTC but should still give the same day in UTC + const formattedDate = formatDateCveDetails(isoString); + + expect(formattedDate).toBe("09/20/2023"); + }); + + it("should return 'N/A' for an invalid date string", () => { + const invalidDate = "invalid-date"; + const formattedDate = formatDateCveDetails(invalidDate); + + expect(formattedDate).toBe("N/A"); + }); + + it("should return 'N/A' for undefined input", () => { + const formattedDate = formatDateCveDetails(undefined); + + expect(formattedDate).toBe("N/A"); + }); +}); diff --git a/utils/helpers/revision-history.js b/utils/helpers/revision-history.js new file mode 100644 index 0000000000..29f9a36647 --- /dev/null +++ b/utils/helpers/revision-history.js @@ -0,0 +1,104 @@ +const { formatDateCveDetails } = require("./date"); + +/** + * Generates a markdown table for revision history, sorted by newest entries first + * @param {Array} revisions - An array of revision objects + * @returns {string} - The markdown table as a string + */ +function generateRevisionHistory(revisions) { + const headers = ["Date", "Revision"]; + const headerRow = `| ${headers.join(" | ")} |`; + const separatorRow = `| ${headers.map(() => "---").join(" | ")} |`; + + // Sort revisions by timestamp in descending order, only if revisions array is not empty + const sortedRevisions = revisions.length + ? [...revisions].sort((a, b) => new Date(b.revisionTimestamp) - new Date(a.revisionTimestamp)) + : []; + + const rows = sortedRevisions.reduce((acc, { revisionTimestamp, revisedField, revisedFrom, revisedTo }) => { + const description = getItemDescription(revisedField, revisedFrom, revisedTo); + + if (!description) return acc; + + const formattedDate = formatDateCveDetails(revisionTimestamp); + acc.push(`| ${formattedDate} | ${description} |`); + return acc; + }, []); + + return `${headerRow}\n${separatorRow}\n${rows.join("\n")}`; +} + +/** + * Generates a description for a revision item based on field, from, and to values + * @param {string} revisedField - The field that was revised + * @param {string} revisedFrom - The previous value of the field + * @param {string} revisedTo - The new value of the field + * @returns {string} - A human-readable description of the revision + */ +function getItemDescription(revisedField, revisedFrom, revisedTo) { + let itemDescription = ""; + + revisedField = revisedField.replace(/(\r\n|\n|\r)/gm, ""); + revisedFrom = revisedFrom.replace(/(\r\n|\n|\r)/gm, ""); + revisedTo = revisedTo.replace(/(\r\n|\n|\r)/gm, ""); + + switch (revisedField) { + case "spec.assessment.justification": + itemDescription = getJustificationDescription(revisedFrom, revisedTo); + break; + + case "metadata.nistSeverity": + itemDescription = getSeverityDescription(revisedFrom, revisedTo); + break; + + case "spec.impact.impactedVersions": + itemDescription = getImpactedVersionsDescription(revisedFrom, revisedTo); + break; + + case "status.status": + itemDescription = revisedFrom !== revisedTo ? `Status changed from ${revisedFrom} to ${revisedTo}` : ""; + break; + + case "spec.impact.isImpacting": + itemDescription = + revisedFrom === "false" && revisedTo === "true" + ? "Advisory is now impacting." + : revisedFrom === "true" && revisedTo === "false" + ? "Advisory is no longer impacting." + : ""; + break; + + default: + return ""; // Return early if no matching case + } + + return itemDescription; +} + +function getJustificationDescription(revisedFrom, revisedTo) { + if (!revisedFrom && revisedTo) return "Official summary added"; + if (revisedFrom && !revisedTo) return "Official summary removed"; + if (revisedFrom && revisedTo) return `Official summary revised: ${revisedTo}`; + return ""; +} + +function getSeverityDescription(revisedFrom, revisedTo) { + if (revisedFrom === "UNKNOWN") return `Advisory assigned with ${revisedTo} severity`; + if (revisedFrom !== revisedTo) return `Advisory severity revised to ${revisedTo} from ${revisedFrom}`; + return ""; +} + +function getImpactedVersionsDescription(revisedFrom, revisedTo) { + const formattedFrom = formatArray(revisedFrom); + const formattedTo = formatArray(revisedTo); + + return revisedFrom === "[]" + ? `Added impacted versions: ${formattedTo}` + : `Impacted versions changed from ${formattedFrom} to ${formattedTo}`; +} + +function formatArray(value) { + return value.replace(/\s+/g, ", ").replace(/^\[|\]$/g, ""); +} + +module.exports = { generateRevisionHistory }; diff --git a/utils/helpers/revision-history.test.js b/utils/helpers/revision-history.test.js new file mode 100644 index 0000000000..396cf48a4c --- /dev/null +++ b/utils/helpers/revision-history.test.js @@ -0,0 +1,186 @@ +const { generateRevisionHistory } = require("./revision-history"); + +describe("generateRevisionHistory", () => { + it("should generate history for justification field changes", () => { + const revisionHistory = [ + { + revisionTimestamp: "2024-10-16T05:50:00.194Z", + revisedField: "spec.assessment.justification", + revisedFrom: "", + revisedTo: "Summary text added", + }, + { + revisionTimestamp: "2024-10-17T05:50:00.194Z", + revisedField: "spec.assessment.justification", + revisedFrom: "Summary text added", + revisedTo: "Revised summary text", + }, + { + revisionTimestamp: "2024-10-18T05:50:00.194Z", + revisedField: "spec.assessment.justification", + revisedFrom: "Revised summary text", + revisedTo: "", + }, + ]; + + const expectedOutput = [ + "| Date | Revision |", + "| --- | --- |", + "| 10/18/2024 | Official summary removed |", + "| 10/17/2024 | Official summary revised: Revised summary text |", + "| 10/16/2024 | Official summary added |", + ].join("\n"); + + expect(generateRevisionHistory(revisionHistory)).toBe(expectedOutput); + }); + + it("should generate history for NIST severity changes", () => { + const revisionHistory = [ + { + revisionTimestamp: "2024-10-16T05:50:00.194Z", + revisedField: "metadata.nistSeverity", + revisedFrom: "UNKNOWN", + revisedTo: "CRITICAL", + }, + { + revisionTimestamp: "2024-10-17T05:50:00.194Z", + revisedField: "metadata.nistSeverity", + revisedFrom: "CRITICAL", + revisedTo: "HIGH", + }, + ]; + + const expectedOutput = [ + "| Date | Revision |", + "| --- | --- |", + "| 10/17/2024 | Advisory severity revised to HIGH from CRITICAL |", + "| 10/16/2024 | Advisory assigned with CRITICAL severity |", + ].join("\n"); + + expect(generateRevisionHistory(revisionHistory)).toBe(expectedOutput); + }); + + it("should generate history for impacted versions changes", () => { + const revisionHistory = [ + { + revisionTimestamp: "2024-10-16T05:50:00.194Z", + revisedField: "spec.impact.impactedVersions", + revisedFrom: "[]", + revisedTo: "[4.4.20]", + }, + { + revisionTimestamp: "2024-10-17T05:50:00.194Z", + revisedField: "spec.impact.impactedVersions", + revisedFrom: "[4.4.20]", + revisedTo: "[4.4.20 4.5.3]", + }, + ]; + + const expectedOutput = [ + "| Date | Revision |", + "| --- | --- |", + "| 10/17/2024 | Impacted versions changed from 4.4.20 to 4.4.20, 4.5.3 |", + "| 10/16/2024 | Added impacted versions: 4.4.20 |", + ].join("\n"); + + expect(generateRevisionHistory(revisionHistory)).toBe(expectedOutput); + }); + + it("should generate history for status changes", () => { + const revisionHistory = [ + { + revisionTimestamp: "2024-10-16T05:50:00.194Z", + revisedField: "status.status", + revisedFrom: "OPEN", + revisedTo: "CLOSED", + }, + ]; + + const expectedOutput = [ + "| Date | Revision |", + "| --- | --- |", + "| 10/16/2024 | Status changed from OPEN to CLOSED |", + ].join("\n"); + + expect(generateRevisionHistory(revisionHistory)).toBe(expectedOutput); + }); + + it("should generate history for isImpacting changes", () => { + const revisionHistory = [ + { + revisionTimestamp: "2024-10-16T05:50:00.194Z", + revisedField: "spec.impact.isImpacting", + revisedFrom: "false", + revisedTo: "true", + }, + { + revisionTimestamp: "2024-10-17T05:50:00.194Z", + revisedField: "spec.impact.isImpacting", + revisedFrom: "true", + revisedTo: "false", + }, + ]; + + const expectedOutput = [ + "| Date | Revision |", + "| --- | --- |", + "| 10/17/2024 | Advisory is no longer impacting. |", + "| 10/16/2024 | Advisory is now impacting. |", + ].join("\n"); + + expect(generateRevisionHistory(revisionHistory)).toBe(expectedOutput); + }); + + it("should sort revisions with newest entries at the top", () => { + const revisionHistory = [ + { + revisionTimestamp: "2024-10-15T05:50:00.194Z", + revisedField: "spec.assessment.justification", + revisedFrom: "", + revisedTo: "Initial summary", + }, + { + revisionTimestamp: "2024-10-17T05:50:00.194Z", + revisedField: "spec.assessment.justification", + revisedFrom: "Initial summary", + revisedTo: "Updated summary", + }, + { + revisionTimestamp: "2024-10-16T05:50:00.194Z", + revisedField: "spec.assessment.justification", + revisedFrom: "Updated summary", + revisedTo: "Final summary", + }, + ]; + + const expectedOutput = [ + "| Date | Revision |", + "| --- | --- |", + "| 10/17/2024 | Official summary revised: Updated summary |", + "| 10/16/2024 | Official summary revised: Final summary |", + "| 10/15/2024 | Official summary added |", + ].join("\n"); + + expect(generateRevisionHistory(revisionHistory)).toBe(expectedOutput); + }); + + it("newlines are removed from description", () => { + const revisionHistory = [ + { + revisionTimestamp: "2024-10-15T05:50:00.194Z", + revisedField: "spec.assessment.justification", + revisedFrom: "Investigation is ongoing to determine how this vulnerability impacts our products.\n", + revisedTo: + "This vulnerability in pam_access allows hostname spoofing to bypass restrictions intended for specific local TTYs or services This enables attackers with minimal effort to exploit gaps in security policies that rely on access.conf configurations. \n\nThis is reported on a few of the third party images which do not use pam_access. So risk of exploitation is low. Impact of exploit is also low, since these containers present a minimal attack surface.\n", + }, + ]; + + const expectedOutput = [ + "| Date | Revision |", + "| --- | --- |", + "| 10/15/2024 | Official summary revised: This vulnerability in pam_access allows hostname spoofing to bypass restrictions intended for specific local TTYs or services This enables attackers with minimal effort to exploit gaps in security policies that rely on access.conf configurations. This is reported on a few of the third party images which do not use pam_access. So risk of exploitation is low. Impact of exploit is also low, since these containers present a minimal attack surface. |", + ].join("\n"); + + expect(generateRevisionHistory(revisionHistory)).toBe(expectedOutput); + }); +}); diff --git a/utils/helpers/string.js b/utils/helpers/string.js new file mode 100644 index 0000000000..dbbe068ba5 --- /dev/null +++ b/utils/helpers/string.js @@ -0,0 +1,16 @@ +function escapeMDXSpecialChars(str) { + if (typeof str !== "string") { + return ""; + } + + // Escape special MDX characters by adding a backslash in front of them + return str + .replace(/\\/g, "\\\\") // Escape backslash + .replace(/{/g, "\\{") // Escape opening curly brace + .replace(/}/g, "\\}") // Escape closing curly brace + .replace(/`/g, "\\`") // Escape backticks + .replace(//g, "\\>"); // Escape greater-than sign +} + +module.exports = { escapeMDXSpecialChars }; diff --git a/utils/helpers/string.test.js b/utils/helpers/string.test.js new file mode 100644 index 0000000000..f2e54ee3b1 --- /dev/null +++ b/utils/helpers/string.test.js @@ -0,0 +1,57 @@ +const { escapeMDXSpecialChars } = require("./string"); + +describe("escapeMDXSpecialChars", () => { + it("should escape all special MDX characters", () => { + const input = "\\ { } ` < >"; + const expectedOutput = "\\\\ \\{ \\} \\` \\< \\>"; + + expect(escapeMDXSpecialChars(input)).toBe(expectedOutput); + }); + + it("should handle strings without special characters", () => { + const input = "Hello World"; + const expectedOutput = "Hello World"; + + expect(escapeMDXSpecialChars(input)).toBe(expectedOutput); + }); + + it("should return an empty string if input is not a string", () => { + expect(escapeMDXSpecialChars(null)).toBe(""); + expect(escapeMDXSpecialChars(123)).toBe(""); + expect(escapeMDXSpecialChars({})).toBe(""); + expect(escapeMDXSpecialChars([])).toBe(""); + expect(escapeMDXSpecialChars(undefined)).toBe(""); + }); + + it("should escape only MDX special characters and leave others intact", () => { + const input = "Hello {world} is a `test` \\ string!"; + const expectedOutput = "Hello \\{world\\} \\ is a \\`test\\` \\\\ string!"; + + expect(escapeMDXSpecialChars(input)).toBe(expectedOutput); + }); + + it("should handle a string with only backslashes correctly", () => { + const input = "\\\\"; + const expectedOutput = "\\\\\\\\"; + + expect(escapeMDXSpecialChars(input)).toBe(expectedOutput); + }); + + it("should escape MDX special characters when they appear multiple times", () => { + const input = "{}{}<<>>``"; + const expectedOutput = "\\{\\}\\{\\}\\<\\<\\>\\>\\`\\`"; + + expect(escapeMDXSpecialChars(input)).toBe(expectedOutput); + }); + + it("should handle an empty string input", () => { + expect(escapeMDXSpecialChars("")).toBe(""); + }); + + it("should not modify numeric characters or punctuation marks other than MDX special characters", () => { + const input = "12345 ,.!? "; + const expectedOutput = "12345 ,.!? "; + + expect(escapeMDXSpecialChars(input)).toBe(expectedOutput); + }); +});