@cryptotaxi247 / CoPilot / commits / a938c6e4

Scoutsuite gcp (#290)

* scoutesuite gcp * bitdefender markdown fix * update back to main * remove bash commands from markdown was causing DB to crash * set back to main * chore: update vue dependencies * refactor: improve variable validation on sigma file upload * feat: add new GCP form * refactor: improve type definitions and style * gcp more modular * precommit fixes --------- Co-authored-by: Davide Di Modica <webmaster.ddm@gmail.com>

taylor_socfortress committed Sep 12, 2024 at 10:55 UTC a938c6e4ac46827f844efce9186bbf5c7c87c2a1
14 files changed +310 -559
backend/app/integrations/markdown/bitdefender.md
+2 -43
@@ -13,7 +13,7 @@ The connector uses the POST method to receive authenticated and secured messages
13 What we will be deploying is an HTTP endpoint that will receive the BitDefender logs and forward them to a syslog server. The HTTP endpoint is running on the server running CoPilot and will be listening on the port that you will define. This means that we must configure public DNS records to point to your edge firewall and open the port that you will define in the firewall.
14
15 Traffic flow will be as follows:
16 -BitDefender Cloud Platform -> Your Edge Firewall -> CoPilot Server -> Graylog Server
16 +BitDefender Cloud Platform _ Your Edge Firewall _ CoPilot Server \_ Graylog Server
17
18 ## Configuration
19
@@ -59,45 +59,4 @@ You should now see the container running.
59
60 ## Test the Connector
61
62 -[Helpful Doc](https://support.netenrich.com/hc/en-us/articles/10833633251869-Bitdefender-Gravity-Zone-Cloud-integration#:~:text=155.173,Configure%20Chronicle%20Forwarder)
63 -
64 -Use the following cURL command to send the test payload to the collector service you have just configured:
65 -
66 -Replace `YOUR_AUTH_HEADER` with the base64 (https://www.blitter.se/utils/basic-authentication-header-generator/) encoded string of `username:password` and `REPLACE_WITH_YOUR_WEBSERVER` with the public DNS name you configured.
67 -
68 -### NOTE: This only tests that your endpoint is reachable and that the logs are being sent to the endpoint. You will need to verify that the logs are being sent to the Graylog server.
69 -
70 -```bash
71 -curl -k -H 'Authorization: Basic YOUR_AUTH_HEADER' -H "Content-Type: application/json" -d
72 -'{"cef": "0","events":
73 -["CEF:0|Bitdefender|GravityZone|6.4.08|70000|Registration|3|BitdefenderGZModule=registrationd
74 -vchost=TEST_ENDPOINTasdadBitdefenderGZComputerFQDN=test.example.com
75 -dvc=192.168.1.2","CEF:0|Bitdefender|GravityZone|6.4.0-8|35|
76 -Product ModulesStatus|5|BitdefenderGZModule=modules
77 -dvchost=TEST_ENDPOINTasdadBitdefenderGZComputerFQDN=test.example.com
78 -dvc=192.168.1.2","CEF:0|Bitdefender|GravityZone|6.4.0-8|35|
79 -Product ModulesStatus|5|BitdefenderGZModule=modules
80 -dvchost=TEST_ENDPOINTasdadBitdefenderGZComputerFQDN=test.example.com dvc=192.168.1.2"]}'
81 -https://REPLACE_WITH_YOUR_WEBSERVER:3200/api
82 -```
83 -
84 -Now that the HTTPS collector service is running and listening for messages, we can test the service by sending a test message to the BitDefender service. Use the following cURL command to send the test payload to the collector service you have just configured:
85 -
86 -Replace `YOUR_BITDEFENDER_API_KEY` with the BitDefender API key with the base64 encoded string of `API_KEY` followed by a colon `:`. For example, if the API key is `test`, the value I would base64 encode would be `test:`. Replace `REPLACE_WITH_YOUR_WEBSERVER` with the public DNS name you configured.
87 -
88 -```bash
89 -$ curl --tlsv1.2 -sS -k -X POST \
90 -https://cloud.gravityzone.bitdefender.com/api/v1.0/jsonrpc/push \
91 --H 'authorization: Basic YOUR_BITDEFENDER_API_KEY' \
92 --H 'cache-control: no-cache' \
93 --H 'content-type: application/json' \
94 --d '{"id":"1","jsonrpc":"2.0","method":"setPushEventSettings",
95 -"params":{"serviceSettings":{"requireValidSslCertificate":false,"authorization":"Basic
96 -dGVzdDp0ZXN0","url":"https://REPLACE_WITH_YOUR_WEBSERVER:3200/api"},"serviceType":"jsonRPC","status":1,
97 -"subscribeToEventTypes":{"adcloudgz":true,"antiexploit":true,"aph":true,"av":true,"avc":true,"dp":true,
98 -"endpoint-moved-in":true,"endpoint-moved-out":true,"exchange-malware":true,
99 -"exchange-user-credentials":true,"fw":true,"hd":true,"hwid-change":true,"install":true,"modules":true,
100 -"network-monitor":true,"network-sandboxing":true,"new-incident":true,"ransomware-mitigation":true,
101 -"registration":true,"supa-update-status":true,"sva":true,"sva-load":true,"task-status":true,
102 -"troubleshooting-activity":true,"uc":true,"uninstall":true}}}'
103 -```
62 +[Helpful Doc For Testing](https://support.netenrich.com/hc/en-us/articles/10833633251869-Bitdefender-Gravity-Zone-Cloud-integration#:~:text=155.173,Configure%20Chronicle%20Forwarder)
backend/app/integrations/scoutsuite/routes/scoutsuite.py
+46
@@ -2,7 +2,9 @@ import os
2
3 from fastapi import APIRouter
4 from fastapi import BackgroundTasks
5 +from fastapi import File
6 from fastapi import HTTPException
7 +from fastapi import UploadFile
8 from loguru import logger
9
10 from app.integrations.scoutsuite.schema.scoutsuite import (
@@ -10,6 +12,7 @@ from app.integrations.scoutsuite.schema.scoutsuite import (
12 )
13 from app.integrations.scoutsuite.schema.scoutsuite import AWSScoutSuiteReportRequest
14 from app.integrations.scoutsuite.schema.scoutsuite import AzureScoutSuiteReportRequest
15 +from app.integrations.scoutsuite.schema.scoutsuite import GCPScoutSuiteReportRequest
16 from app.integrations.scoutsuite.schema.scoutsuite import ScoutSuiteReportOptions
17 from app.integrations.scoutsuite.schema.scoutsuite import (
18 ScoutSuiteReportOptionsResponse,
@@ -21,6 +24,12 @@ from app.integrations.scoutsuite.services.scoutsuite import (
24 from app.integrations.scoutsuite.services.scoutsuite import (
25 generate_azure_report_background,
26 )
27 +from app.integrations.scoutsuite.services.scoutsuite import (
28 + generate_gcp_report_background,
29 +)
30 +from app.integrations.scoutsuite.services.scoutsuite import read_json_file
31 +from app.integrations.scoutsuite.services.scoutsuite import save_file_to_directory
32 +from app.integrations.scoutsuite.services.scoutsuite import validate_json_data
33
34 integration_scoutsuite_router = APIRouter()
35
@@ -122,6 +131,43 @@ async def generate_azure_report(
131 )
132
133
134 +@integration_scoutsuite_router.post(
135 + "/generate-gcp-report",
136 + response_model=ScoutSuiteReportResponse,
137 +)
138 +async def generate_gcp_report(
139 + background_tasks: BackgroundTasks,
140 + file: UploadFile = File(...),
141 + report_name: str = "gcp-report",
142 +):
143 + """
144 + Endpoint to generate a GCP ScoutSuite report.
145 +
146 + Args:
147 + background_tasks (BackgroundTasks): The background tasks object.
148 + file (UploadFile): The uploaded JSON file.
149 + """
150 + # Read the file contents
151 + contents = await file.read()
152 +
153 + # Read and validate the JSON file
154 + data = await read_json_file(contents)
155 + validate_json_data(data)
156 +
157 + # Save the file to the scoutsuite-report directory
158 + directory = os.path.join(os.getcwd(), "scoutsuite-report")
159 + file_path = await save_file_to_directory(contents, directory, file.filename)
160 +
161 + logger.info(f"File saved to: {file_path}")
162 + request = GCPScoutSuiteReportRequest(report_name=report_name, file_path=file_path)
163 + logger.info(f"Request: {request}")
164 + background_tasks.add_task(generate_gcp_report_background, request)
165 + return ScoutSuiteReportResponse(
166 + success=True,
167 + message="GCP ScoutSuite report generation started successfully. This will take a few minutes to complete. Check back in shortly.",
168 + )
169 +
170 +
171 @integration_scoutsuite_router.delete(
172 "/delete-report/{report_name}",
173 response_model=ScoutSuiteReportResponse,
backend/app/integrations/scoutsuite/schema/scoutsuite.py
+19
@@ -52,6 +52,25 @@ class AzureScoutSuiteReportRequest(BaseModel):
52 return values
53
54
55 +class GCPScoutSuiteReportRequest(BaseModel):
56 + report_name: str = Field(..., description="The name of the report", example="gcp-report")
57 + file_path: str = Field(..., description="The path to the GCP credentials file", example="gcp-credentials.json")
58 +
59 +
60 +class GCPScoutSuiteJSON(BaseModel):
61 + type: str
62 + project_id: str
63 + private_key_id: str
64 + private_key: str
65 + client_email: str
66 + client_id: str
67 + auth_uri: str
68 + token_uri: str
69 + auth_provider_x509_cert_url: str
70 + client_x509_cert_url: str
71 + universe_domain: str
72 +
73 +
74 class ScoutSuiteReportResponse(BaseModel):
75 success: bool
76 message: str
backend/app/integrations/scoutsuite/services/scoutsuite.py
+62
@@ -1,11 +1,17 @@
1 import asyncio
2 +import json
3 +import os
4 import subprocess
5 from concurrent.futures import ThreadPoolExecutor
6
7 +import aiofiles
8 +from fastapi import HTTPException
9 from loguru import logger
10
11 from app.integrations.scoutsuite.schema.scoutsuite import AWSScoutSuiteReportRequest
12 from app.integrations.scoutsuite.schema.scoutsuite import AzureScoutSuiteReportRequest
13 +from app.integrations.scoutsuite.schema.scoutsuite import GCPScoutSuiteJSON
14 +from app.integrations.scoutsuite.schema.scoutsuite import GCPScoutSuiteReportRequest
15
16
17 async def generate_aws_report_background(request: AWSScoutSuiteReportRequest):
@@ -57,6 +63,34 @@ def construct_azure_command(request: AzureScoutSuiteReportRequest):
63 ]
64
65
66 +async def generate_gcp_report_background(request: GCPScoutSuiteReportRequest):
67 + logger.info("Generating GCP ScoutSuite report in the background")
68 +
69 + command = construct_gcp_command(request)
70 + await run_command_in_background(command)
71 +
72 + # Delete the file after the report is generated
73 + try:
74 + os.remove(request.file_path)
75 + logger.info(f"Deleted GCP credentials file: {request.file_path}")
76 + except Exception as e:
77 + logger.error(f"Error deleting GCP credentials file: {e}")
78 +
79 +
80 +def construct_gcp_command(request: GCPScoutSuiteReportRequest):
81 + """Construct the scout command."""
82 + return [
83 + "scout",
84 + "gcp",
85 + "--service-account",
86 + request.file_path,
87 + "--report-name",
88 + request.report_name,
89 + "--force",
90 + "--no-browser",
91 + ]
92 +
93 +
94 def run_command(command):
95 """Run the command and handle the output."""
96 process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -75,3 +109,31 @@ async def run_command_in_background(command):
109 with ThreadPoolExecutor() as executor:
110 loop = asyncio.get_event_loop()
111 await loop.run_in_executor(executor, lambda: run_command(command))
112 +
113 +
114 +async def read_json_file(contents: bytes) -> dict:
115 + """Read and parse the JSON file."""
116 + try:
117 + return json.loads(contents)
118 + except json.JSONDecodeError as e:
119 + raise HTTPException(status_code=400, detail=f"Invalid JSON file - {str(e)}")
120 +
121 +
122 +def validate_json_data(data: dict):
123 + """Validate the JSON data against the GCPScoutSuiteJSON model."""
124 + try:
125 + GCPScoutSuiteJSON(**data)
126 + except Exception as e:
127 + raise HTTPException(status_code=400, detail=f"JSON file does not have the correct format and fields - {str(e)}")
128 +
129 +
130 +async def save_file_to_directory(contents: bytes, directory: str, filename: str) -> str:
131 + """Save the uploaded file to the specified directory."""
132 + try:
133 + os.makedirs(directory, exist_ok=True)
134 + file_path = os.path.join(directory, filename)
135 + async with aiofiles.open(file_path, "wb") as out_file:
136 + await out_file.write(contents)
137 + return file_path
138 + except Exception as e:
139 + raise HTTPException(status_code=400, detail=str(e))
frontend/package-lock.json
+42 -497
@@ -10,9 +10,9 @@
10 "dependencies": {
11 "@ajoelp/json-to-formdata": "^1.5.0",
12 "@f3ve/vue-markdown-it": "^0.2.2",
13 - "@fontsource/jetbrains-mono": "^5.0.22",
14 - "@fontsource/lexend": "^5.0.22",
15 - "@fontsource/public-sans": "^5.0.18",
13 + "@fontsource/jetbrains-mono": "^5.1.0",
14 + "@fontsource/lexend": "^5.1.0",
15 + "@fontsource/public-sans": "^5.1.0",
16 "@popperjs/core": "^2.11.8",
17 "@shikijs/markdown-it": "^1.17.0",
18 "@vueuse/components": "^11.0.3",
@@ -41,7 +41,7 @@
41 "vue": "^3.5.4",
42 "vue-advanced-cropper": "^2.8.9",
43 "vue-highlight-words": "^3.0.1",
44 - "vue-i18n": "^10.0.0",
44 + "vue-i18n": "^10.0.1",
45 "vue-router": "^4.4.4",
46 "vue-sjv": "^0.0.6",
47 "vue3-apexcharts": "^1.6.0",
@@ -83,8 +83,8 @@
83 "sass": "^1.78.0",
84 "start-server-and-test": "^2.0.7",
85 "tailwind-config-viewer": "^2.0.4",
86 - "tailwindcss": "^3.4.10",
87 - "taze": "^0.16.7",
86 + "tailwindcss": "^3.4.11",
87 + "taze": "^0.16.8",
88 "type-fest": "^4.26.1",
89 "unplugin-vue-components": "^0.27.4",
90 "vite": "^5.4.4",
@@ -99,7 +99,7 @@
99 "node": ">=18.0.0"
100 },
101 "optionalDependencies": {
102 - "@rollup/rollup-linux-x64-gnu": "^4.21.2"
102 + "@rollup/rollup-linux-x64-gnu": "^4.21.3"
103 }
104 },
105 "node_modules/@ajoelp/json-to-formdata": {
@@ -1413,19 +1413,19 @@
1413 }
1414 },
1415 "node_modules/@fontsource/jetbrains-mono": {
1416 - "version": "5.0.22",
1417 - "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-5.0.22.tgz",
1418 - "integrity": "sha512-eFjS3ilq9n9FeRCdSSDhj3BTtr74FYeJswSJr9VDIxb02A07sQ59VugLuq1EKs6eLha+IOT5+4qVpllGaQNNHg=="
1416 + "version": "5.1.0",
1417 + "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-5.1.0.tgz",
1418 + "integrity": "sha512-YzWpGYY3PoqvmvwW2Hb4NwkN5C7LO0FmZugEGcFe6cNNE/cMgH9JhW5LI6hjG+1+nwgSHyJtKmblHNrUqlyhWg=="
1419 },
1420 "node_modules/@fontsource/lexend": {
1421 - "version": "5.0.22",
1422 - "resolved": "https://registry.npmjs.org/@fontsource/lexend/-/lexend-5.0.22.tgz",
1423 - "integrity": "sha512-Eb1T9KamX8rK4dCl3t/rL9a0uFp2/L477HO0I11RIZWdrDR3iQ4vx6L5hd866VrzH6H0TGPLfuW+jstbZeFeWA=="
1421 + "version": "5.1.0",
1422 + "resolved": "https://registry.npmjs.org/@fontsource/lexend/-/lexend-5.1.0.tgz",
1423 + "integrity": "sha512-mqwRfsRobLoj4iHqkvMGMMiTYU7n0hbgGftGBKFGKGyedseQOQ3k7iCBVTAU9wIyfq02Rypd9BrLXChHwFvg0Q=="
1424 },
1425 "node_modules/@fontsource/public-sans": {
1426 - "version": "5.0.18",
1427 - "resolved": "https://registry.npmjs.org/@fontsource/public-sans/-/public-sans-5.0.18.tgz",
1428 - "integrity": "sha512-dYx/ULF7pRkjBO1ncCwIRXWWmI2oCsMsWxheHgjtNANm4+prtfq3gdGy3KOsuNcAhEKn6BQeIyg0hFqeoTpAaQ=="
1426 + "version": "5.1.0",
1427 + "resolved": "https://registry.npmjs.org/@fontsource/public-sans/-/public-sans-5.1.0.tgz",
1428 + "integrity": "sha512-94+468XL9dUxsZ5edw/AtBHLdIwkvqr3WBUMBD30LUQzJpHw/Fxd7VrgkXSIKRIwYi3pTuQ1Q2Vj3COGIwi58Q=="
1429 },
1430 "node_modules/@hapi/hoek": {
1431 "version": "9.3.0",
@@ -1488,12 +1488,12 @@
1488 }
1489 },
1490 "node_modules/@intlify/core-base": {
1491 - "version": "10.0.0",
1492 - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.0.tgz",
1493 - "integrity": "sha512-o4d4Nve7YzU1YMR5VMqgPr8jDGTgT2pOOUtZa3JwCAhFnm40JYxfHdWToT7OEx6oJCBs/Q8HosJOhsimlF0C0Q==",
1491 + "version": "10.0.1",
1492 + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.1.tgz",
1493 + "integrity": "sha512-6kpRGjhos95ph7QmEtP4tnWFTW102s71CLQAQwfsIGqOAcoJhzcYFpzIQ0gKXzqAIXsMD/hwM5qJ4ewqMHw3gg==",
1494 "dependencies": {
1495 - "@intlify/message-compiler": "10.0.0",
1496 - "@intlify/shared": "10.0.0"
1495 + "@intlify/message-compiler": "10.0.1",
1496 + "@intlify/shared": "10.0.1"
1497 },
1498 "engines": {
1499 "node": ">= 16"
@@ -1503,11 +1503,11 @@
1503 }
1504 },
1505 "node_modules/@intlify/message-compiler": {
1506 - "version": "10.0.0",
1507 - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.0.tgz",
1508 - "integrity": "sha512-OcaWc63NC/9p1cMdgoNKBj4d61BH8sUW1Hfs6YijTd9656ZR4rNqXAlRnBrfS5ABq0vjQjpa8VnyvH9hK49yBw==",
1506 + "version": "10.0.1",
1507 + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.1.tgz",
1508 + "integrity": "sha512-fPeykrcgVT5eOIlshTHiPCN8FV3AZyBOdMS3XaXzfQ6eL5wqfc29I/EdIv5YXVW5X8e/BgYeWjBC0Cuznsl/2g==",
1509 "dependencies": {
1510 - "@intlify/shared": "10.0.0",
1510 + "@intlify/shared": "10.0.1",
1511 "source-map-js": "^1.0.2"
1512 },
1513 "engines": {
@@ -1518,9 +1518,9 @@
1518 }
1519 },
1520 "node_modules/@intlify/shared": {
1521 - "version": "10.0.0",
1522 - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.0.tgz",
1523 - "integrity": "sha512-6ngLfI7DOTew2dcF9WMJx+NnMWghMBhIiHbGg+wRvngpzD5KZJZiJVuzMsUQE1a5YebEmtpTEfUrDp/NqVGdiw==",
1521 + "version": "10.0.1",
1522 + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.1.tgz",
1523 + "integrity": "sha512-b4h7IWdZl710DnAhET8lgfgZ4Y9A2IZx/gbli3Ec/zHtYCoPqLHmiM7kUNBrSZj7d/SSjcMMZHuz5I09x3PYZw==",
1524 "engines": {
1525 "node": ">= 16"
1526 },
@@ -1691,49 +1691,6 @@
1691 "node": ">= 8"
1692 }
1693 },
1694 - "node_modules/@npmcli/agent": {
1695 - "version": "2.2.2",
1696 - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz",
1697 - "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==",
1698 - "dev": true,
1699 - "dependencies": {
1700 - "agent-base": "^7.1.0",
1701 - "http-proxy-agent": "^7.0.0",
1702 - "https-proxy-agent": "^7.0.1",
1703 - "lru-cache": "^10.0.1",
1704 - "socks-proxy-agent": "^8.0.3"
1705 - },
1706 - "engines": {
1707 - "node": "^16.14.0 || >=18.0.0"
1708 - }
1709 - },
1710 - "node_modules/@npmcli/agent/node_modules/lru-cache": {
1711 - "version": "10.4.3",
1712 - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
1713 - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
1714 - "dev": true
1715 - },
1716 - "node_modules/@npmcli/fs": {
1717 - "version": "3.1.1",
1718 - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz",
1719 - "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==",
1720 - "dev": true,
1721 - "dependencies": {
1722 - "semver": "^7.3.5"
1723 - },
1724 - "engines": {
1725 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
1726 - }
1727 - },
1728 - "node_modules/@npmcli/redact": {
1729 - "version": "2.0.1",
1730 - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.1.tgz",
1731 - "integrity": "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==",
1732 - "dev": true,
1733 - "engines": {
1734 - "node": "^16.14.0 || >=18.0.0"
1735 - }
1736 - },
1694 "node_modules/@nuxt/kit": {
1695 "version": "3.13.1",
1696 "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.13.1.tgz",
@@ -2034,9 +1991,9 @@
1991 ]
1992 },
1993 "node_modules/@rollup/rollup-linux-x64-gnu": {
2037 - "version": "4.21.2",
2038 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz",
2039 - "integrity": "sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==",
1994 + "version": "4.21.3",
1995 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz",
1996 + "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==",
1997 "cpu": [
1998 "x64"
1999 ],
@@ -4072,35 +4029,6 @@
4029 "node": ">=8"
4030 }
4031 },
4075 - "node_modules/cacache": {
4076 - "version": "18.0.4",
4077 - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz",
4078 - "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==",
4079 - "dev": true,
4080 - "dependencies": {
4081 - "@npmcli/fs": "^3.1.0",
4082 - "fs-minipass": "^3.0.0",
4083 - "glob": "^10.2.2",
4084 - "lru-cache": "^10.0.1",
4085 - "minipass": "^7.0.3",
4086 - "minipass-collect": "^2.0.1",
4087 - "minipass-flush": "^1.0.5",
4088 - "minipass-pipeline": "^1.2.4",
4089 - "p-map": "^4.0.0",
4090 - "ssri": "^10.0.0",
4091 - "tar": "^6.1.11",
4092 - "unique-filename": "^3.0.0"
4093 - },
4094 - "engines": {
4095 - "node": "^16.14.0 || >=18.0.0"
4096 - }
4097 - },
4098 - "node_modules/cacache/node_modules/lru-cache": {
4099 - "version": "10.4.3",
4100 - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
4101 - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
4102 - "dev": true
4103 - },
4032 "node_modules/cache-content-type": {
4033 "version": "1.0.1",
4034 "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz",
@@ -5356,16 +5284,6 @@
5284 "node": ">= 0.8"
5285 }
5286 },
5359 - "node_modules/encoding": {
5360 - "version": "0.1.13",
5361 - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
5362 - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
5363 - "dev": true,
5364 - "optional": true,
5365 - "dependencies": {
5366 - "iconv-lite": "^0.6.2"
5367 - }
5368 - },
5287 "node_modules/end-of-stream": {
5288 "version": "1.4.4",
5289 "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@@ -5399,12 +5317,6 @@
5317 "url": "https://github.com/fb55/entities?sponsor=1"
5318 }
5319 },
5402 - "node_modules/err-code": {
5403 - "version": "2.0.3",
5404 - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
5405 - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
5406 - "dev": true
5407 - },
5320 "node_modules/error-stack-parser-es": {
5321 "version": "0.1.5",
5322 "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz",
@@ -6292,18 +6204,6 @@
6204 "node": ">=14.14"
6205 }
6206 },
6295 - "node_modules/fs-minipass": {
6296 - "version": "3.0.3",
6297 - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz",
6298 - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==",
6299 - "dev": true,
6300 - "dependencies": {
6301 - "minipass": "^7.0.3"
6302 - },
6303 - "engines": {
6304 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
6305 - }
6306 - },
6207 "node_modules/fs.realpath": {
6208 "version": "1.0.0",
6209 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -6692,24 +6592,6 @@
6592 "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
6593 "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="
6594 },
6695 - "node_modules/hosted-git-info": {
6696 - "version": "7.0.2",
6697 - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
6698 - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
6699 - "dev": true,
6700 - "dependencies": {
6701 - "lru-cache": "^10.0.1"
6702 - },
6703 - "engines": {
6704 - "node": "^16.14.0 || >=18.0.0"
6705 - }
6706 - },
6707 - "node_modules/hosted-git-info/node_modules/lru-cache": {
6708 - "version": "10.4.3",
6709 - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
6710 - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
6711 - "dev": true
6712 - },
6595 "node_modules/html-encoding-sniffer": {
6596 "version": "4.0.0",
6597 "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
@@ -6805,12 +6687,6 @@
6687 "node": ">= 0.6"
6688 }
6689 },
6808 - "node_modules/http-cache-semantics": {
6809 - "version": "4.1.1",
6810 - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
6811 - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
6812 - "dev": true
6813 - },
6690 "node_modules/http-errors": {
6691 "version": "2.0.0",
6692 "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -7031,25 +6907,6 @@
6907 "node": ">=10"
6908 }
6909 },
7034 - "node_modules/ip-address": {
7035 - "version": "9.0.5",
7036 - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
7037 - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
7038 - "dev": true,
7039 - "dependencies": {
7040 - "jsbn": "1.1.0",
7041 - "sprintf-js": "^1.1.3"
7042 - },
7043 - "engines": {
7044 - "node": ">= 12"
7045 - }
7046 - },
7047 - "node_modules/ip-address/node_modules/jsbn": {
7048 - "version": "1.1.0",
7049 - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
7050 - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
7051 - "dev": true
7052 - },
6910 "node_modules/is-binary-path": {
6911 "version": "2.1.0",
6912 "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -7195,12 +7052,6 @@
7052 "url": "https://github.com/sponsors/sindresorhus"
7053 }
7054 },
7198 - "node_modules/is-lambda": {
7199 - "version": "1.0.1",
7200 - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
7201 - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
7202 - "dev": true
7203 - },
7055 "node_modules/is-number": {
7056 "version": "7.0.0",
7057 "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -7532,15 +7383,6 @@
7383 "graceful-fs": "^4.1.6"
7384 }
7385 },
7535 - "node_modules/jsonparse": {
7536 - "version": "1.3.1",
7537 - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
7538 - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
7539 - "dev": true,
7540 - "engines": [
7541 - "node >= 0.2.0"
7542 - ]
7543 - },
7386 "node_modules/jsprim": {
7387 "version": "2.0.2",
7388 "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
@@ -8133,29 +7975,6 @@
7975 "@jridgewell/sourcemap-codec": "^1.5.0"
7976 }
7977 },
8136 - "node_modules/make-fetch-happen": {
8137 - "version": "13.0.1",
8138 - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz",
8139 - "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==",
8140 - "dev": true,
8141 - "dependencies": {
8142 - "@npmcli/agent": "^2.0.0",
8143 - "cacache": "^18.0.0",
8144 - "http-cache-semantics": "^4.1.1",
8145 - "is-lambda": "^1.0.1",
8146 - "minipass": "^7.0.2",
8147 - "minipass-fetch": "^3.0.0",
8148 - "minipass-flush": "^1.0.5",
8149 - "minipass-pipeline": "^1.2.4",
8150 - "negotiator": "^0.6.3",
8151 - "proc-log": "^4.2.0",
8152 - "promise-retry": "^2.0.1",
8153 - "ssri": "^10.0.0"
8154 - },
8155 - "engines": {
8156 - "node": "^16.14.0 || >=18.0.0"
8157 - }
8158 - },
7978 "node_modules/map-stream": {
7979 "version": "0.1.0",
7980 "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
@@ -8405,125 +8224,6 @@
8224 "node": ">=16 || 14 >=14.17"
8225 }
8226 },
8408 - "node_modules/minipass-collect": {
8409 - "version": "2.0.1",
8410 - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz",
8411 - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==",
8412 - "dev": true,
8413 - "dependencies": {
8414 - "minipass": "^7.0.3"
8415 - },
8416 - "engines": {
8417 - "node": ">=16 || 14 >=14.17"
8418 - }
8419 - },
8420 - "node_modules/minipass-fetch": {
8421 - "version": "3.0.5",
8422 - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz",
8423 - "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==",
8424 - "dev": true,
8425 - "dependencies": {
8426 - "minipass": "^7.0.3",
8427 - "minipass-sized": "^1.0.3",
8428 - "minizlib": "^2.1.2"
8429 - },
8430 - "engines": {
8431 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
8432 - },
8433 - "optionalDependencies": {
8434 - "encoding": "^0.1.13"
8435 - }
8436 - },
8437 - "node_modules/minipass-flush": {
8438 - "version": "1.0.5",
8439 - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
8440 - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
8441 - "dev": true,
8442 - "dependencies": {
8443 - "minipass": "^3.0.0"
8444 - },
8445 - "engines": {
8446 - "node": ">= 8"
8447 - }
8448 - },
8449 - "node_modules/minipass-flush/node_modules/minipass": {
8450 - "version": "3.3.6",
8451 - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
8452 - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
8453 - "dev": true,
8454 - "dependencies": {
8455 - "yallist": "^4.0.0"
8456 - },
8457 - "engines": {
8458 - "node": ">=8"
8459 - }
8460 - },
8461 - "node_modules/minipass-flush/node_modules/yallist": {
8462 - "version": "4.0.0",
8463 - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
8464 - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
8465 - "dev": true
8466 - },
8467 - "node_modules/minipass-pipeline": {
8468 - "version": "1.2.4",
8469 - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
8470 - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
8471 - "dev": true,
8472 - "dependencies": {
8473 - "minipass": "^3.0.0"
8474 - },
8475 - "engines": {
8476 - "node": ">=8"
8477 - }
8478 - },
8479 - "node_modules/minipass-pipeline/node_modules/minipass": {
8480 - "version": "3.3.6",
8481 - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
8482 - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
8483 - "dev": true,
8484 - "dependencies": {
8485 - "yallist": "^4.0.0"
8486 - },
8487 - "engines": {
8488 - "node": ">=8"
8489 - }
8490 - },
8491 - "node_modules/minipass-pipeline/node_modules/yallist": {
8492 - "version": "4.0.0",
8493 - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
8494 - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
8495 - "dev": true
8496 - },
8497 - "node_modules/minipass-sized": {
8498 - "version": "1.0.3",
8499 - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
8500 - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
8501 - "dev": true,
8502 - "dependencies": {
8503 - "minipass": "^3.0.0"
8504 - },
8505 - "engines": {
8506 - "node": ">=8"
8507 - }
8508 - },
8509 - "node_modules/minipass-sized/node_modules/minipass": {
8510 - "version": "3.3.6",
8511 - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
8512 - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
8513 - "dev": true,
8514 - "dependencies": {
8515 - "yallist": "^4.0.0"
8516 - },
8517 - "engines": {
8518 - "node": ">=8"
8519 - }
8520 - },
8521 - "node_modules/minipass-sized/node_modules/yallist": {
8522 - "version": "4.0.0",
8523 - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
8524 - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
8525 - "dev": true
8526 - },
8227 "node_modules/minizlib": {
8228 "version": "2.1.2",
8229 "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
@@ -8730,40 +8430,6 @@
8430 "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
8431 }
8432 },
8733 - "node_modules/npm-package-arg": {
8734 - "version": "11.0.3",
8735 - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz",
8736 - "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==",
8737 - "dev": true,
8738 - "dependencies": {
8739 - "hosted-git-info": "^7.0.0",
8740 - "proc-log": "^4.0.0",
8741 - "semver": "^7.3.5",
8742 - "validate-npm-package-name": "^5.0.0"
8743 - },
8744 - "engines": {
8745 - "node": "^16.14.0 || >=18.0.0"
8746 - }
8747 - },
8748 - "node_modules/npm-registry-fetch": {
8749 - "version": "17.1.0",
8750 - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz",
8751 - "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==",
8752 - "dev": true,
8753 - "dependencies": {
8754 - "@npmcli/redact": "^2.0.0",
8755 - "jsonparse": "^1.3.1",
8756 - "make-fetch-happen": "^13.0.0",
8757 - "minipass": "^7.0.2",
8758 - "minipass-fetch": "^3.0.0",
8759 - "minizlib": "^2.1.2",
8760 - "npm-package-arg": "^11.0.0",
8761 - "proc-log": "^4.0.0"
8762 - },
8763 - "engines": {
8764 - "node": "^16.14.0 || >=18.0.0"
8765 - }
8766 - },
8433 "node_modules/npm-run-all2": {
8434 "version": "6.2.2",
8435 "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.2.2.tgz",
@@ -9677,15 +9343,6 @@
9343 "url": "https://github.com/sponsors/sindresorhus"
9344 }
9345 },
9680 - "node_modules/proc-log": {
9681 - "version": "4.2.0",
9682 - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz",
9683 - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==",
9684 - "dev": true,
9685 - "engines": {
9686 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
9687 - }
9688 - },
9346 "node_modules/process": {
9347 "version": "0.11.10",
9348 "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@@ -9695,19 +9352,6 @@
9352 "node": ">= 0.6.0"
9353 }
9354 },
9698 - "node_modules/promise-retry": {
9699 - "version": "2.0.1",
9700 - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
9701 - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
9702 - "dev": true,
9703 - "dependencies": {
9704 - "err-code": "^2.0.2",
9705 - "retry": "^0.12.0"
9706 - },
9707 - "engines": {
9708 - "node": ">=10"
9709 - }
9710 - },
9355 "node_modules/property-information": {
9356 "version": "6.5.0",
9357 "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz",
@@ -10127,15 +9771,6 @@
9771 "node": ">=8"
9772 }
9773 },
10130 - "node_modules/retry": {
10131 - "version": "0.12.0",
10132 - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
10133 - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
10134 - "dev": true,
10135 - "engines": {
10136 - "node": ">= 4"
10137 - }
10138 - },
9774 "node_modules/reusify": {
9775 "version": "1.0.4",
9776 "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -10546,44 +10181,6 @@
10181 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
10182 "dev": true
10183 },
10549 - "node_modules/smart-buffer": {
10550 - "version": "4.2.0",
10551 - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
10552 - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
10553 - "dev": true,
10554 - "engines": {
10555 - "node": ">= 6.0.0",
10556 - "npm": ">= 3.0.0"
10557 - }
10558 - },
10559 - "node_modules/socks": {
10560 - "version": "2.8.3",
10561 - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
10562 - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
10563 - "dev": true,
10564 - "dependencies": {
10565 - "ip-address": "^9.0.5",
10566 - "smart-buffer": "^4.2.0"
10567 - },
10568 - "engines": {
10569 - "node": ">= 10.0.0",
10570 - "npm": ">= 3.0.0"
10571 - }
10572 - },
10573 - "node_modules/socks-proxy-agent": {
10574 - "version": "8.0.4",
10575 - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz",
10576 - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==",
10577 - "dev": true,
10578 - "dependencies": {
10579 - "agent-base": "^7.1.1",
10580 - "debug": "^4.3.4",
10581 - "socks": "^2.8.3"
10582 - },
10583 - "engines": {
10584 - "node": ">= 14"
10585 - }
10586 - },
10184 "node_modules/sortablejs": {
10185 "version": "1.14.0",
10186 "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
@@ -10636,12 +10233,6 @@
10233 "node": "*"
10234 }
10235 },
10639 - "node_modules/sprintf-js": {
10640 - "version": "1.1.3",
10641 - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
10642 - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
10643 - "dev": true
10644 - },
10236 "node_modules/sshpk": {
10237 "version": "1.18.0",
10238 "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
@@ -10667,18 +10258,6 @@
10258 "node": ">=0.10.0"
10259 }
10260 },
10670 - "node_modules/ssri": {
10671 - "version": "10.0.6",
10672 - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz",
10673 - "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==",
10674 - "dev": true,
10675 - "dependencies": {
10676 - "minipass": "^7.0.3"
10677 - },
10678 - "engines": {
10679 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
10680 - }
10681 - },
10261 "node_modules/stackback": {
10262 "version": "0.0.2",
10263 "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
@@ -11135,9 +10714,9 @@
10714 }
10715 },
10716 "node_modules/tailwindcss": {
11138 - "version": "3.4.10",
11139 - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz",
11140 - "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==",
10717 + "version": "3.4.11",
10718 + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.11.tgz",
10719 + "integrity": "sha512-qhEuBcLemjSJk5ajccN9xJFtM/h0AVCPaA6C92jNP+M2J8kX+eMJHI7R2HFKUvvAsMpcfLILMCFYSeDwpMmlUg==",
10720 "dev": true,
10721 "dependencies": {
10722 "@alloc/quick-lru": "^5.2.0",
@@ -11234,14 +10813,13 @@
10813 "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
10814 },
10815 "node_modules/taze": {
11237 - "version": "0.16.7",
11238 - "resolved": "https://registry.npmjs.org/taze/-/taze-0.16.7.tgz",
11239 - "integrity": "sha512-bVKeFJc/rewVI5MFcG8EK5+6jWx37c3IiDy9qnk9Pv6FV8OLu6GhTk1ru+KLmvGwQc2twqtKA8HW3HmjHA2bEQ==",
10816 + "version": "0.16.8",
10817 + "resolved": "https://registry.npmjs.org/taze/-/taze-0.16.8.tgz",
10818 + "integrity": "sha512-vrkKrpVxkLrvSJ5Hc0FNheaJGoxv+uxzMWbGJCpucUpN5CnUlfvdL+mK98LGVqQZSjaPcAbkSQ/08N520ddLaQ==",
10819 "dev": true,
10820 "dependencies": {
10821 "@antfu/ni": "^0.23.0",
10822 "js-yaml": "^4.1.0",
11244 - "npm-registry-fetch": "^17.1.0",
10823 "ofetch": "^1.3.4",
10824 "package-manager-detector": "^0.2.0",
10825 "tinyexec": "^0.3.0",
@@ -11665,30 +11243,6 @@
11243 "@types/estree": "^1.0.0"
11244 }
11245 },
11668 - "node_modules/unique-filename": {
11669 - "version": "3.0.0",
11670 - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz",
11671 - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==",
11672 - "dev": true,
11673 - "dependencies": {
11674 - "unique-slug": "^4.0.0"
11675 - },
11676 - "engines": {
11677 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
11678 - }
11679 - },
11680 - "node_modules/unique-slug": {
11681 - "version": "4.0.0",
11682 - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz",
11683 - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==",
11684 - "dev": true,
11685 - "dependencies": {
11686 - "imurmurhash": "^0.1.4"
11687 - },
11688 - "engines": {
11689 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
11690 - }
11691 - },
11246 "node_modules/unist-util-is": {
11247 "version": "6.0.0",
11248 "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz",
@@ -11920,15 +11474,6 @@
11474 "uuid": "dist/bin/uuid"
11475 }
11476 },
11923 - "node_modules/validate-npm-package-name": {
11924 - "version": "5.0.1",
11925 - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz",
11926 - "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==",
11927 - "dev": true,
11928 - "engines": {
11929 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
11930 - }
11931 - },
11477 "node_modules/validator": {
11478 "version": "13.12.0",
11479 "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
@@ -12701,12 +12246,12 @@
12246 }
12247 },
12248 "node_modules/vue-i18n": {
12704 - "version": "10.0.0",
12705 - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.0.tgz",
12706 - "integrity": "sha512-KxTfTEuZEGN5Bvgc9F49rgp94XyBFlSIszwF2SQlr3WoxOklySXdUuoVxIw5qPZthV0mJlGP8tjJR7loMJgKrQ==",
12249 + "version": "10.0.1",
12250 + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.1.tgz",
12251 + "integrity": "sha512-SQVlSm/1S6AaG1wexvwq3ebXUrrkx75ZHD78UAs4/rYD/X3tsQxfm6ElpT4ZPegJQEgRtOJjGripqSrfqAENtg==",
12252 "dependencies": {
12708 - "@intlify/core-base": "10.0.0",
12709 - "@intlify/shared": "10.0.0",
12253 + "@intlify/core-base": "10.0.1",
12254 + "@intlify/shared": "10.0.1",
12255 "@vue/devtools-api": "^6.5.0"
12256 },
12257 "engines": {
frontend/package.json
+7 -7
@@ -32,9 +32,9 @@
32 "dependencies": {
33 "@ajoelp/json-to-formdata": "^1.5.0",
34 "@f3ve/vue-markdown-it": "^0.2.2",
35 - "@fontsource/jetbrains-mono": "^5.0.22",
36 - "@fontsource/lexend": "^5.0.22",
37 - "@fontsource/public-sans": "^5.0.18",
35 + "@fontsource/jetbrains-mono": "^5.1.0",
36 + "@fontsource/lexend": "^5.1.0",
37 + "@fontsource/public-sans": "^5.1.0",
38 "@popperjs/core": "^2.11.8",
39 "@shikijs/markdown-it": "^1.17.0",
40 "@vueuse/components": "^11.0.3",
@@ -63,7 +63,7 @@
63 "vue": "^3.5.4",
64 "vue-advanced-cropper": "^2.8.9",
65 "vue-highlight-words": "^3.0.1",
66 - "vue-i18n": "^10.0.0",
66 + "vue-i18n": "^10.0.1",
67 "vue-router": "^4.4.4",
68 "vue-sjv": "^0.0.6",
69 "vue3-apexcharts": "^1.6.0",
@@ -105,8 +105,8 @@
105 "sass": "^1.78.0",
106 "start-server-and-test": "^2.0.7",
107 "tailwind-config-viewer": "^2.0.4",
108 - "tailwindcss": "^3.4.10",
109 - "taze": "^0.16.7",
108 + "tailwindcss": "^3.4.11",
109 + "taze": "^0.16.8",
110 "type-fest": "^4.26.1",
111 "unplugin-vue-components": "^0.27.4",
112 "vite": "^5.4.4",
@@ -118,7 +118,7 @@
118 "vue-tsc": "^2.1.6"
119 },
120 "optionalDependencies": {
121 - "@rollup/rollup-linux-x64-gnu": "^4.21.2"
121 + "@rollup/rollup-linux-x64-gnu": "^4.21.3"
122 },
123 "overrides": {
124 "@vue/eslint-config-typescript": {
frontend/src/api/endpoints/cloudSecurityAssessment.ts
+11
@@ -3,6 +3,7 @@ import { HttpClient } from "../httpClient"
3 import type {
4 ScoutSuiteAwsReportPayload,
5 ScoutSuiteAzureReportPayload,
6 + ScoutSuiteGcpReportPayload,
7 ScoutSuiteReport,
8 ScoutSuiteReportPayload
9 } from "@/types/cloudSecurityAssessment.d"
@@ -25,6 +26,16 @@ export default {
26 report_type: "azure"
27 })
28 },
29 + generateGcpScoutSuiteReport(payload: ScoutSuiteReportPayload & ScoutSuiteGcpReportPayload) {
30 + const form = new FormData()
31 + form.append("file", new Blob([payload.file], { type: payload.file.type }), payload.file.name)
32 +
33 + return HttpClient.post<FlaskBaseResponse>(`/scoutsuite/generate-gcp-report`, form, {
34 + params: {
35 + report_name: payload.report_name
36 + }
37 + })
38 + },
39 deleteScoutSuiteReport(reportName: string) {
40 return HttpClient.delete<FlaskBaseResponse>(`/scoutsuite/delete-report/${reportName}`)
41 }
frontend/src/components/cloudSecurityAssessment/AvailableReportsList.vue
+1 -1
@@ -50,7 +50,7 @@
50 v-model:show="showForm"
51 display-directive="show"
52 preset="card"
53 - :style="{ maxWidth: 'min(600px, 90vw)', minHeight: 'min(300px, 90vh)', overflow: 'hidden' }"
53 + :style="{ maxWidth: 'min(600px, 90vw)', minHeight: 'min(270px, 90vh)', overflow: 'hidden' }"
54 title="Generate Report"
55 :bordered="false"
56 segmented
frontend/src/components/cloudSecurityAssessment/CreationReportForm.vue
+25 -5
@@ -35,6 +35,13 @@
35 @mounted="typeFormRef = $event"
36 />
37
38 + <GcpTypeForm
39 + v-if="baseForm.report_type === ScoutSuiteReportType.Gcp"
40 + @model="typeForm = $event"
41 + @valid="typeFormValid = $event"
42 + @mounted="typeFormRef = $event"
43 + />
44 +
45 <div class="flex justify-between gap-4 mt-8">
46 <n-button @click="reset()" :disabled="loading">Reset</n-button>
47 <n-button
@@ -70,15 +77,17 @@ import {
77 import {
78 type ScoutSuiteAwsReportPayload,
79 type ScoutSuiteAzureReportPayload,
80 + type ScoutSuiteGcpReportPayload,
81 type ScoutSuiteReportPayload,
82 ScoutSuiteReportType
83 } from "@/types/cloudSecurityAssessment.d"
84 import AwsTypeForm from "./FormTypes/AwsTypeForm.vue"
85 import AzureTypeForm from "./FormTypes/AzureTypeForm.vue"
86 +import GcpTypeForm from "./FormTypes/GcpTypeForm.vue"
87 import type { ApiError, ApiCommonResponse } from "@/types/common.d"
88
89 type BaseFormPayload = Omit<ScoutSuiteReportPayload, "report_type"> & { report_type: ScoutSuiteReportType | null }
81 -type TypeFormPayload = ScoutSuiteAwsReportPayload | ScoutSuiteAzureReportPayload
90 +type TypeFormPayload = Partial<ScoutSuiteAwsReportPayload | ScoutSuiteAzureReportPayload | ScoutSuiteGcpReportPayload>
91
92 const emit = defineEmits<{
93 (e: "submitted"): void
@@ -100,7 +109,7 @@ const typeFormValid = ref<boolean>(false)
109 const baseFormRef = ref<FormInst | null>(null)
110 const typeFormRef = ref<FormInst | null>(null)
111
103 -const availableTypes = ["aws", "azure"]
112 +const availableTypes = ["aws", "azure", "gcp"]
113
114 const reportTypeOptions = ref<{ label: string; value: string; disabled: boolean }[]>([])
115
@@ -207,6 +216,13 @@ function submit() {
216 ...(typeForm.value as ScoutSuiteAzureReportPayload)
217 })
218 break
219 + case ScoutSuiteReportType.Gcp:
220 + apiCall = Api.cloudSecurityAssessment.generateGcpScoutSuiteReport({
221 + ...baseForm.value,
222 + report_type: ScoutSuiteReportType.Gcp,
223 + ...(typeForm.value as ScoutSuiteGcpReportPayload)
224 + })
225 + break
226 }
227
228 if (!apiCall) {
@@ -218,9 +234,13 @@ function submit() {
234 apiCall
235 .then(res => {
236 if (res.data.success) {
221 - message.success(res.data?.message || `ScoutSuite report generation started successfully`, {
222 - duration: 10 * 1000
223 - })
237 + message.success(
238 + res.data?.message ||
239 + `ScoutSuite report generation started successfully. This will take a few minutes to complete. Check back in shortly.`,
240 + {
241 + duration: 10 * 1000
242 + }
243 + )
244 emit("submitted")
245 resetForm()
246 } else {
frontend/src/components/cloudSecurityAssessment/FormTypes/AwsTypeForm.vue
+2 -2
@@ -24,11 +24,11 @@ import type { ScoutSuiteAwsReportPayload } from "@/types/cloudSecurityAssessment
24
25 const emit = defineEmits<{
26 (e: "mounted", value: FormInst): void
27 - (e: "model", value: ScoutSuiteAwsReportPayload): void
27 + (e: "model", value: Partial<ScoutSuiteAwsReportPayload>): void
28 (e: "valid", value: boolean): void
29 }>()
30
31 -const form = ref<ScoutSuiteAwsReportPayload>({
31 +const form = ref<Partial<ScoutSuiteAwsReportPayload>>({
32 access_key_id: "",
33 secret_access_key: ""
34 })
frontend/src/components/cloudSecurityAssessment/FormTypes/AzureTypeForm.vue
+2 -2
@@ -29,11 +29,11 @@ import type { ScoutSuiteAzureReportPayload } from "@/types/cloudSecurityAssessme
29
30 const emit = defineEmits<{
31 (e: "mounted", value: FormInst): void
32 - (e: "model", value: ScoutSuiteAzureReportPayload): void
32 + (e: "model", value: Partial<ScoutSuiteAzureReportPayload>): void
33 (e: "valid", value: boolean): void
34 }>()
35
36 -const form = ref<ScoutSuiteAzureReportPayload>({
36 +const form = ref<Partial<ScoutSuiteAzureReportPayload>>({
37 username: "",
38 password: "",
39 tenant_id: ""
frontend/src/components/cloudSecurityAssessment/FormTypes/GcpTypeForm.vue new
+85
@@ -0,0 +1,85 @@
1 +<template>
2 + <n-form :model="form" :rules="rules" ref="formRef">
3 + <div class="flex flex-col gap-2">
4 + <n-form-item label="Configuration file" path="file">
5 + <n-upload :max="1" accept="application/json, .json, .JSON" v-model:file-list="fileList">
6 + <n-upload-dragger>
7 + <div>
8 + <Icon :name="UploadIcon" :size="28" :depth="3"></Icon>
9 + </div>
10 + <div class="font-semibold">Click or drag a file to this area to upload</div>
11 + <p class="mt-2">Only .json files are accepted</p>
12 + </n-upload-dragger>
13 + </n-upload>
14 + </n-form-item>
15 + </div>
16 + </n-form>
17 +</template>
18 +
19 +<script setup lang="ts">
20 +import { computed, onMounted, ref, watch } from "vue"
21 +import {
22 + NForm,
23 + NFormItem,
24 + NUpload,
25 + NUploadDragger,
26 + type FormRules,
27 + type FormInst,
28 + type UploadFileInfo,
29 + type FormItemRule
30 +} from "naive-ui"
31 +import Icon from "@/components/common/Icon.vue"
32 +import type { ScoutSuiteGcpReportPayload } from "@/types/cloudSecurityAssessment.d"
33 +
34 +const emit = defineEmits<{
35 + (e: "mounted", value: FormInst): void
36 + (e: "model", value: Partial<ScoutSuiteGcpReportPayload>): void
37 + (e: "valid", value: boolean): void
38 +}>()
39 +
40 +const form = ref<Partial<ScoutSuiteGcpReportPayload>>({
41 + file: undefined
42 +})
43 +const formRef = ref<FormInst>()
44 +const UploadIcon = "carbon:document-add"
45 +const fileList = ref<UploadFileInfo[]>([])
46 +const jsonFile = computed<File | null>(() => fileList.value?.[0]?.file || null)
47 +const rules: FormRules = {
48 + file: {
49 + required: true,
50 + validator: validateFile,
51 + trigger: ["input", "blur"]
52 + }
53 +}
54 +
55 +const isValid = computed(() => {
56 + if (!form.value.file) return false
57 + return true
58 +})
59 +
60 +function validateFile(rule: FormItemRule, value: File | undefined) {
61 + if (rule.required && !value) {
62 + return new Error("Please input the Configuration file")
63 + }
64 +
65 + return true
66 +}
67 +
68 +watch(
69 + jsonFile,
70 + val => {
71 + form.value.file = val || undefined
72 + },
73 + { deep: true, immediate: true }
74 +)
75 +
76 +watch(form, val => emit("model", val), { deep: true, immediate: true })
77 +
78 +watch(isValid, val => emit("valid", val), { immediate: true })
79 +
80 +onMounted(() => {
81 + if (formRef.value) {
82 + emit("mounted", formRef.value)
83 + }
84 +})
85 +</script>
frontend/src/components/sigma/actionsProviders/QueryUploadFile.vue
+1 -1
@@ -48,7 +48,7 @@ const show = ref(false)
48 const lastShow = ref(new Date().getTime())
49 const message = useMessage()
50 const fileList = ref<UploadFileInfo[]>([])
51 -const yamlFile = computed<File | null>(() => fileList.value?.[0].file || null)
51 +const yamlFile = computed<File | null>(() => fileList.value?.[0]?.file || null)
52 const isValid = computed(() => fileList.value.length)
53
54 function togglePopup() {
frontend/src/types/cloudSecurityAssessment.d.ts
+5 -1
@@ -2,7 +2,8 @@ export type ScoutSuiteReport = string
2
3 export enum ScoutSuiteReportType {
4 AWS = "aws",
5 - Azure = "azure"
5 + Azure = "azure",
6 + Gcp = "gcp"
7 }
8 export interface ScoutSuiteReportPayload {
9 report_type: ScoutSuiteReportType
@@ -17,3 +18,6 @@ export interface ScoutSuiteAzureReportPayload {
18 password: string
19 tenant_id: string
20 }
21 +export interface ScoutSuiteGcpReportPayload {
22 + file: File
23 +}