@cryptotaxi247 / CoPilot / commits / 1414cbb5

823 auth endpoints (#824)

* feat: add security dependency to Cato provisioning route Co-authored-by: Copilot <copilot@github.com> * feat: add security dependency to exclude Wazuh rule endpoint Co-authored-by: Copilot <copilot@github.com> * feat: add security dependency to sync vulnerabilities route Co-authored-by: Copilot <copilot@github.com> * feat: add security dependency to Graylog receiver endpoint Co-authored-by: Copilot <copilot@github.com> * feat: remove artifact recommendation and file collection endpoints * feat: add security dependency to receive sublime alert endpoint Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to Patch Tuesday endpoints Co-authored-by: Copilot <copilot@github.com> * feat: add security dependency to create report endpoint Co-authored-by: Copilot <copilot@github.com> * feat: enable security dependencies for create integration endpoints Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to Mimecast routes for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to detection rule endpoints for admin, analyst, and customer_user roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to monitoring alert provision routes for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to SAP SIEM provisioning route for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to sysmon config routes for admin role Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to provision route for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to various license routes for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to various integration routes for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to SAP SIEM routes for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to create network connector routes for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to Nuclei report routes for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to provision route for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to AI trigger and notification routes for admin, analyst, and customer user roles * feat: add security dependencies to incident alert routes for admin, analyst, and customer user roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to report generation routes for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * feat: add security dependencies to provision route for admin and analyst roles Co-authored-by: Copilot <copilot@github.com> * precommit-fixes * feat: update current version to 0.1.59 --------- Co-authored-by: Copilot <copilot@github.com>

taylor_socfortress committed Apr 25, 2026 at 15:42 UTC 1414cbb5d574a1bb08ff32cc2be77763799a2442
32 files changed +542 -147
backend/app/active_response/routes/sysmon_config.py
+19 -5
@@ -4,6 +4,7 @@ from fastapi import File
4 from fastapi import Form
5 from fastapi import HTTPException
6 from fastapi import Response
7 +from fastapi import Security
8 from fastapi import UploadFile
9 from sqlalchemy.ext.asyncio import AsyncSession
10
@@ -14,6 +15,7 @@ from app.active_response.schema.sysmon_config import SysmonConfigUploadResponse
15 from app.active_response.services.sysmon_config import check_config_exists
16 from app.active_response.services.sysmon_config import deploy_sysmon_config_to_worker
17 from app.active_response.services.sysmon_config import validate_sysmon_config
18 +from app.auth.routes.auth import AuthHandler
19 from app.data_store.data_store_operations import download_sysmon_config
20 from app.data_store.data_store_operations import list_sysmon_configs
21 from app.data_store.data_store_operations import upload_sysmon_config
@@ -22,7 +24,11 @@ from app.db.db_session import get_db
24 sysmon_config_router = APIRouter()
25
26
25 -@sysmon_config_router.post("/upload", response_model=SysmonConfigUploadResponse)
27 +@sysmon_config_router.post(
28 + "/upload",
29 + response_model=SysmonConfigUploadResponse,
30 + dependencies=[Security(AuthHandler().require_any_scope("admin"))],
31 +)
32 async def upload_customer_sysmon_config(
33 customer_code: str = Form(...),
34 file: UploadFile = File(...),
@@ -60,7 +66,11 @@ async def upload_customer_sysmon_config(
66
67
68 # This route must come before the /{customer_code} route
63 -@sysmon_config_router.get("/content/{customer_code}", response_model=SysmonConfigContentResponse)
69 +@sysmon_config_router.get(
70 + "/content/{customer_code}",
71 + response_model=SysmonConfigContentResponse,
72 + dependencies=[Security(AuthHandler().require_any_scope("admin"))],
73 +)
74 async def get_customer_sysmon_config_content(customer_code: str, session: AsyncSession = Depends(get_db)):
75 """Get the sysmon config for a specific customer as a string."""
76 try:
@@ -81,7 +91,7 @@ async def get_customer_sysmon_config_content(customer_code: str, session: AsyncS
91 raise HTTPException(status_code=500, detail=f"Error retrieving config: {str(e)}")
92
93
84 -@sysmon_config_router.get("", response_model=SysmonConfigListResponse)
94 +@sysmon_config_router.get("", response_model=SysmonConfigListResponse, dependencies=[Security(AuthHandler().require_any_scope("admin"))])
95 async def get_all_sysmon_configs(session: AsyncSession = Depends(get_db)):
96 """List all customers that have sysmon configs."""
97 customers = await list_sysmon_configs()
@@ -93,7 +103,7 @@ async def get_all_sysmon_configs(session: AsyncSession = Depends(get_db)):
103 )
104
105
96 -@sysmon_config_router.get("/{customer_code}")
106 +@sysmon_config_router.get("/{customer_code}", dependencies=[Security(AuthHandler().require_any_scope("admin"))])
107 async def get_customer_sysmon_config(customer_code: str, session: AsyncSession = Depends(get_db)):
108 """Download the sysmon config for a specific customer."""
109 try:
@@ -109,7 +119,11 @@ async def get_customer_sysmon_config(customer_code: str, session: AsyncSession =
119 raise HTTPException(status_code=500, detail=f"Error retrieving config: {str(e)}")
120
121
112 -@sysmon_config_router.post("/deploy/{customer_code}", response_model=SysmonConfigDeploymentResult)
122 +@sysmon_config_router.post(
123 + "/deploy/{customer_code}",
124 + response_model=SysmonConfigDeploymentResult,
125 + dependencies=[Security(AuthHandler().require_any_scope("admin"))],
126 +)
127 async def deploy_sysmon_config(customer_code: str, session: AsyncSession = Depends(get_db)):
128 """
129 Deploy a customer's Sysmon config to the Wazuh master.
backend/app/agents/routes/agents.py
+1
@@ -1292,6 +1292,7 @@ async def delete_agent(
1292 @agents_router.get(
1293 "/sync/vulnerabilities",
1294 description="Sync agent vulnerabilities",
1295 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
1296 )
1297 async def sync_vulnerabilities_route(
1298 session: AsyncSession = Depends(get_db),
backend/app/connectors/grafana/routes/reporting.py
+1
@@ -218,6 +218,7 @@ async def generate_grafana_iframe_links(
218 "/generate-report",
219 response_model=GenerateReportResponse,
220 description="Create a new report.",
221 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
222 )
223 async def create_report(request: GenerateReportRequest, session: AsyncSession = Depends(get_db)) -> GenerateReportResponse:
224 logger.info("Generating report")
backend/app/connectors/graylog/routes/receiver.py
+3
@@ -1,6 +1,8 @@
1 from fastapi import APIRouter
2 +from fastapi import Security
3 from loguru import logger
4
5 +from app.auth.routes.auth import AuthHandler
6 from app.integrations.utils.event_shipper import event_shipper
7 from app.integrations.utils.schema import EventShipperPayload
8
@@ -17,6 +19,7 @@ graylog_receiver_router = APIRouter()
19 @graylog_receiver_router.post(
20 "/receiver",
21 description="Forward a message to Graylog",
22 + dependencies=[Security(AuthHandler().require_any_scope("admin"))],
23 )
24 async def forward_to_graylog(payload: dict) -> dict:
25 """
backend/app/connectors/sublime/routes/alerts.py
+1
@@ -18,6 +18,7 @@ sublime_alerts_router = APIRouter()
18 @sublime_alerts_router.post(
19 "/alert",
20 description="Receive alert from Sublime and store it in the database",
21 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
22 )
23 async def receive_sublime_alert(
24 alert_request_body: AlertRequestBody,
backend/app/connectors/velociraptor/routes/artifacts.py
-53
@@ -10,8 +10,6 @@ from sqlalchemy.future import select
10
11 from app.auth.utils import AuthHandler
12 from app.connectors.velociraptor.schema.artifacts import ArtifactParametersResponse
13 -from app.connectors.velociraptor.schema.artifacts import ArtifactReccomendationAIRequest
14 -from app.connectors.velociraptor.schema.artifacts import ArtifactReccomendationRequest
13 from app.connectors.velociraptor.schema.artifacts import ArtifactsResponse
14 from app.connectors.velociraptor.schema.artifacts import CollectArtifactBody
15 from app.connectors.velociraptor.schema.artifacts import CollectArtifactResponse
@@ -28,7 +26,6 @@ from app.connectors.velociraptor.services.artifacts import (
26 get_artifact_parameters_by_prefix_service,
27 )
28 from app.connectors.velociraptor.services.artifacts import get_artifacts
31 -from app.connectors.velociraptor.services.artifacts import post_to_copilot_ai_module
29 from app.connectors.velociraptor.services.artifacts import quarantine_host
30 from app.connectors.velociraptor.services.artifacts import run_artifact_collection
31 from app.connectors.velociraptor.services.artifacts import run_file_collection
@@ -567,56 +564,6 @@ async def quarantine(
564 return quarantine_response
565
566
570 -@velociraptor_artifacts_router.post(
571 - "/velociraptor-artifact-recommendation",
572 - description="Retrieve artifact to run based on alert. Invokes the `copilot-ai-module",
573 -)
574 -async def get_artifact_recommendation(request: ArtifactReccomendationAIRequest):
575 - """
576 - Retrieve the artifact to run based on the alert.
577 -
578 - Returns:
579 - str: The artifact to run based on the alert.
580 - """
581 - logger.info("Fetching artifact recommendation based on alert")
582 - artifacts = await get_artifacts()
583 - logger.info(f"Artifacts: {artifacts.artifacts}")
584 - return await post_to_copilot_ai_module(
585 - data=ArtifactReccomendationRequest(
586 - artifacts=artifacts.artifacts,
587 - os=request.os,
588 - prompt=request.prompt,
589 - ),
590 - )
591 -
592 -
593 -# ! WIP ! #
594 -@velociraptor_artifacts_router.post(
595 - "/collect/file",
596 - response_model=CollectArtifactResponse,
597 - description="Run an the artifact to collect a file",
598 -)
599 -async def collect_file(collect_artifact_body: CollectFileBody, session: AsyncSession = Depends(get_db)):
600 - """
601 - Collects a file based on the artifact.
602 -
603 - Returns:
604 - CollectArtifactResponse: The response containing the collected file.
605 - """
606 - logger.info(f"Received request to collect artifact {collect_artifact_body}")
607 -
608 - collect_artifact_body.velociraptor_id = await get_velociraptor_id(
609 - session,
610 - collect_artifact_body.hostname,
611 - )
612 -
613 - collect_artifact_body.velociraptor_org = await get_velociraptor_org(
614 - session,
615 - collect_artifact_body.hostname,
616 - )
617 - return await run_file_collection(collect_artifact_body, session)
618 -
619 -
567 # Add this new route after the existing collect_file route
568
569
backend/app/connectors/wazuh_manager/routes/rules.py
+1
@@ -176,6 +176,7 @@ async def enable_wazuh_rule(
176 "/rule/exclude",
177 response_model=RuleExcludeResponse,
178 description="Retrieve recommended exclusion for a Wazuh Rule",
179 + dependencies=[Security(AuthHandler().require_any_scope("admin"))],
180 )
181 async def exclude_wazuh_rule(request: RuleExcludeRequest) -> RuleExcludeResponse:
182 return await post_to_copilot_ai_module(data=request)
backend/app/incidents/routes/db_operations.py
+388 -80
@@ -8,6 +8,7 @@ from fastapi import Depends
8 from fastapi import File
9 from fastapi import HTTPException
10 from fastapi import Query
11 +from fastapi import Security
12 from fastapi import UploadFile
13 from fastapi.responses import StreamingResponse
14 from loguru import logger
@@ -240,7 +241,11 @@ from app.middleware.customer_access import customer_access_handler
241 incidents_db_operations_router = APIRouter()
242
243
243 -@incidents_db_operations_router.get("/ai_trigger/{customer_code}", response_model=AITriggerResponse)
244 +@incidents_db_operations_router.get(
245 + "/ai_trigger/{customer_code}",
246 + response_model=AITriggerResponse,
247 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
248 +)
249 async def get_customer_ai_trigger_endpoint(
250 customer_code: str,
251 _customer: Customers = Depends(check_customer_exists),
@@ -253,7 +258,11 @@ async def get_customer_ai_trigger_endpoint(
258 )
259
260
256 -@incidents_db_operations_router.put("/ai_trigger", response_model=AITriggerResponse)
261 +@incidents_db_operations_router.put(
262 + "/ai_trigger",
263 + response_model=AITriggerResponse,
264 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
265 +)
266 async def put_customer_ai_trigger_endpoint(
267 notification: PutAITrigger,
268 _customer: Customers = Depends(check_customer_exists),
@@ -267,7 +276,11 @@ async def put_customer_ai_trigger_endpoint(
276 )
277
278
270 -@incidents_db_operations_router.get("/notification/{customer_code}", response_model=NotificationResponse)
279 +@incidents_db_operations_router.get(
280 + "/notification/{customer_code}",
281 + response_model=NotificationResponse,
282 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
283 +)
284 async def get_customer_notification_endpoint(
285 customer_code: str,
286 _customer: Customers = Depends(check_customer_exists),
@@ -280,7 +293,11 @@ async def get_customer_notification_endpoint(
293 )
294
295
283 -@incidents_db_operations_router.put("/notification", response_model=NotificationResponse)
296 +@incidents_db_operations_router.put(
297 + "/notification",
298 + response_model=NotificationResponse,
299 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
300 +)
301 async def put_customer_notification_endpoint(
302 notification: PutNotification,
303 _customer: Customers = Depends(check_customer_exists),
@@ -294,12 +311,20 @@ async def put_customer_notification_endpoint(
311 )
312
313
297 -@incidents_db_operations_router.get("/available-source/{index_name}", response_model=AvailableSourcesResponse)
314 +@incidents_db_operations_router.get(
315 + "/available-source/{index_name}",
316 + response_model=AvailableSourcesResponse,
317 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
318 +)
319 async def get_available_source_values(index_name: str, session: AsyncSession = Depends(get_db)):
320 return AvailableSourcesResponse(source=await get_index_source(index_name), success=True, message="Source retrieved successfully")
321
322
302 -@incidents_db_operations_router.get("/available-indices/{source}", response_model=AvailableIndicesResponse)
323 +@incidents_db_operations_router.get(
324 + "/available-indices/{source}",
325 + response_model=AvailableIndicesResponse,
326 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
327 +)
328 async def get_available_indices(source: str, session: AsyncSession = Depends(get_db)):
329 return AvailableIndicesResponse(
330 indices=await get_available_indices_via_source(source),
@@ -308,7 +333,11 @@ async def get_available_indices(source: str, session: AsyncSession = Depends(get
333 )
334
335
311 -@incidents_db_operations_router.get("/socfortress/recommends/wazuh", response_model=SocfortressRecommendsWazuhResponse)
336 +@incidents_db_operations_router.get(
337 + "/socfortress/recommends/wazuh",
338 + response_model=SocfortressRecommendsWazuhResponse,
339 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
340 +)
341 async def get_socfortress_recommends_wazuh(session: AsyncSession = Depends(get_db)):
342 return SocfortressRecommendsWazuhResponse(
343 field_names=[field.value for field in SocfortressRecommendsWazuhFieldNames],
@@ -322,14 +351,21 @@ async def get_socfortress_recommends_wazuh(session: AsyncSession = Depends(get_d
351 )
352
353
325 -@incidents_db_operations_router.get("/configured/sources", response_model=ConfiguredSourcesResponse)
354 +@incidents_db_operations_router.get(
355 + "/configured/sources",
356 + response_model=ConfiguredSourcesResponse,
357 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
358 +)
359 async def get_configured_sources(session: AsyncSession = Depends(get_db)):
360 query = select(FieldName.source).distinct()
361 result = await session.execute(query)
362 return ConfiguredSourcesResponse(sources=[row[0] for row in result], success=True, message="Configured sources retrieved successfully")
363
364
332 -@incidents_db_operations_router.delete("/configured/sources/{source}")
365 +@incidents_db_operations_router.delete(
366 + "/configured/sources/{source}",
367 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
368 +)
369 async def delete_configured_source(source: str, session: AsyncSession = Depends(get_db)):
370 # Fully deletes the configured sources `field_names`, `asset_name`, timefield_name`, alert_title_name`
371 field_names = await get_field_names(source, session)
@@ -362,13 +398,21 @@ async def delete_configured_source(source: str, session: AsyncSession = Depends(
398 return {"message": f"Configured source {source} deleted successfully", "success": True}
399
400
365 -@incidents_db_operations_router.get("/mappings/fields-assets-title-and-timefield", response_model=MappingsResponse)
401 +@incidents_db_operations_router.get(
402 + "/mappings/fields-assets-title-and-timefield",
403 + response_model=MappingsResponse,
404 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
405 +)
406 async def get_wazuh_fields_and_assets(index_name: str, session: AsyncSession = Depends(get_db)):
407 index_mapping = await get_index_mappings_key_names(index_name)
408 return MappingsResponse(available_mappings=index_mapping, success=True, message="Field names and asset names retrieved successfully")
409
410
371 -@incidents_db_operations_router.get("/fields-assets-title-and-timefield", response_model=FieldAndAssetNamesResponse)
411 +@incidents_db_operations_router.get(
412 + "/fields-assets-title-and-timefield",
413 + response_model=FieldAndAssetNamesResponse,
414 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
415 +)
416 async def get_source_fields_and_assets(source: str, session: AsyncSession = Depends(get_db)):
417 await validate_source_exists(source, session)
418 return FieldAndAssetNamesResponse(
@@ -383,7 +427,10 @@ async def get_source_fields_and_assets(source: str, session: AsyncSession = Depe
427 )
428
429
386 -@incidents_db_operations_router.post("/fields-assets-title-and-timefield")
430 +@incidents_db_operations_router.post(
431 + "/fields-assets-title-and-timefield",
432 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
433 +)
434 async def create_wazuh_fields_and_assets(names: FieldAndAssetNames, session: AsyncSession = Depends(get_db)):
435 for field_name in names.field_names:
436 await add_field_name(names.source, field_name, session)
@@ -405,7 +452,10 @@ async def create_wazuh_fields_and_assets(names: FieldAndAssetNames, session: Asy
452 return {"message": "Field names and asset names created successfully", "success": True}
453
454
408 -@incidents_db_operations_router.put("/fields-assets-title-and-timefield")
455 +@incidents_db_operations_router.put(
456 + "/fields-assets-title-and-timefield",
457 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
458 +)
459 async def update_fields_and_assets(names: FieldAndAssetNames, session: AsyncSession = Depends(get_db)):
460 await replace_field_name(names.source, names.field_names, session)
461
@@ -420,7 +470,10 @@ async def update_fields_and_assets(names: FieldAndAssetNames, session: AsyncSess
470 return {"message": "Field names and asset names created successfully", "success": True}
471
472
423 -@incidents_db_operations_router.delete("/delete-fields-assets-title-and-timefield")
473 +@incidents_db_operations_router.delete(
474 + "/delete-fields-assets-title-and-timefield",
475 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
476 +)
477 async def delete_wazuh_fields_and_assets(names: FieldAndAssetNames, session: AsyncSession = Depends(get_db)):
478 for field_name in names.field_names:
479 await delete_field_name(names.source, field_name, session)
@@ -441,37 +494,65 @@ async def delete_wazuh_fields_and_assets(names: FieldAndAssetNames, session: Asy
494 return {"message": "Field names and asset names deleted successfully", "success": True}
495
496
444 -@incidents_db_operations_router.delete("/field_name/{field_name}/{source}", deprecated=True)
497 +@incidents_db_operations_router.delete(
498 + "/field_name/{field_name}/{source}",
499 + deprecated=True,
500 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
501 +)
502 async def delete_field_name_endpoint(field_name: str, source: str, db: AsyncSession = Depends(get_db)):
503 return await delete_field_name(source, field_name, db)
504
505
449 -@incidents_db_operations_router.delete("/asset_name/{asset_name}/{source}", deprecated=True)
506 +@incidents_db_operations_router.delete(
507 + "/asset_name/{asset_name}/{source}",
508 + deprecated=True,
509 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
510 +)
511 async def delete_asset_name_endpoint(asset_name: str, source: str, db: AsyncSession = Depends(get_db)):
512 return await delete_asset_name(source, asset_name, db)
513
514
454 -@incidents_db_operations_router.delete("/timefield_name/{timefield_name}/{source}", deprecated=True)
515 +@incidents_db_operations_router.delete(
516 + "/timefield_name/{timefield_name}/{source}",
517 + deprecated=True,
518 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
519 +)
520 async def delete_timefield_name_endpoint(timefield_name: str, source: str, db: AsyncSession = Depends(get_db)):
521 return await delete_timefield_name(source, timefield_name, db)
522
523
459 -@incidents_db_operations_router.delete("/alert_title_name/{alert_title_name}/{source}", deprecated=True)
524 +@incidents_db_operations_router.delete(
525 + "/alert_title_name/{alert_title_name}/{source}",
526 + deprecated=True,
527 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
528 +)
529 async def delete_alert_title_name_endpoint(alert_title_name: str, source: str, db: AsyncSession = Depends(get_db)):
530 return await delete_alert_title_name(source, alert_title_name, db)
531
532
464 -@incidents_db_operations_router.post("/alert", response_model=Alert)
533 +@incidents_db_operations_router.post(
534 + "/alert",
535 + response_model=Alert,
536 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
537 +)
538 async def create_alert_endpoint(alert: AlertCreate, db: AsyncSession = Depends(get_db)):
539 return await create_alert(alert, db)
540
541
469 -@incidents_db_operations_router.put("/alert/status", response_model=AlertResponse)
542 +@incidents_db_operations_router.put(
543 + "/alert/status",
544 + response_model=AlertResponse,
545 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
546 +)
547 async def update_alert_status_endpoint(alert_status: UpdateAlertStatus, db: AsyncSession = Depends(get_db)):
548 return AlertResponse(alert=await update_alert_status(alert_status, db), success=True, message="Alert status updated successfully")
549
550
474 -@incidents_db_operations_router.put("/alert/escalated", response_model=AlertResponse)
551 +@incidents_db_operations_router.put(
552 + "/alert/escalated",
553 + response_model=AlertResponse,
554 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
555 +)
556 async def update_alert_escalated_endpoint(
557 escalate_alert: EscalateAlert,
558 current_user: User = Depends(AuthHandler().get_current_user),
@@ -493,7 +574,11 @@ async def update_alert_escalated_endpoint(
574 return AlertResponse(alert=updated_alert, success=True, message="Alert escalated status updated successfully")
575
576
496 -@incidents_db_operations_router.post("/alert/comment", response_model=CommentResponse)
577 +@incidents_db_operations_router.post(
578 + "/alert/comment",
579 + response_model=CommentResponse,
580 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
581 +)
582 async def create_comment_endpoint(
583 comment: CommentCreate,
584 current_user: User = Depends(AuthHandler().get_current_user),
@@ -509,7 +594,11 @@ async def create_comment_endpoint(
594 return CommentResponse(comment=await create_comment(comment, db), success=True, message="Comment created successfully")
595
596
512 -@incidents_db_operations_router.put("/alert/comment", response_model=CommentResponse)
597 +@incidents_db_operations_router.put(
598 + "/alert/comment",
599 + response_model=CommentResponse,
600 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
601 +)
602 async def edit_comment_endpoint(
603 comment: CommentEdit,
604 current_user: User = Depends(AuthHandler().get_current_user),
@@ -525,7 +614,10 @@ async def edit_comment_endpoint(
614 return CommentResponse(comment=await edit_comment(comment, db), success=True, message="Comment edited successfully")
615
616
528 -@incidents_db_operations_router.delete("/alert/comment/{comment_id}")
617 +@incidents_db_operations_router.delete(
618 + "/alert/comment/{comment_id}",
619 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
620 +)
621 async def delete_comment_endpoint(
622 comment_id: int,
623 current_user: User = Depends(AuthHandler().get_current_user),
@@ -551,7 +643,11 @@ async def delete_comment_endpoint(
643 return {"message": "Comment deleted successfully", "success": True}
644
645
554 -@incidents_db_operations_router.post("/case/comment", response_model=CaseCommentResponse)
646 +@incidents_db_operations_router.post(
647 + "/case/comment",
648 + response_model=CaseCommentResponse,
649 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
650 +)
651 async def create_case_comment_endpoint(
652 comment: CaseCommentCreate,
653 current_user: User = Depends(AuthHandler().get_current_user),
@@ -567,7 +663,11 @@ async def create_case_comment_endpoint(
663 return CaseCommentResponse(comment=await create_case_comment(comment, db), success=True, message="Case comment created successfully")
664
665
570 -@incidents_db_operations_router.put("/case/comment", response_model=CaseCommentResponse)
666 +@incidents_db_operations_router.put(
667 + "/case/comment",
668 + response_model=CaseCommentResponse,
669 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
670 +)
671 async def edit_case_comment_endpoint(
672 comment: CaseCommentEdit,
673 current_user: User = Depends(AuthHandler().get_current_user),
@@ -583,7 +683,10 @@ async def edit_case_comment_endpoint(
683 return CaseCommentResponse(comment=await edit_case_comment(comment, db), success=True, message="Case comment edited successfully")
684
685
586 -@incidents_db_operations_router.delete("/case/comment/{comment_id}")
686 +@incidents_db_operations_router.delete(
687 + "/case/comment/{comment_id}",
688 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
689 +)
690 async def delete_case_comment_endpoint(
691 comment_id: int,
692 current_user: User = Depends(AuthHandler().get_current_user),
@@ -609,7 +712,11 @@ async def delete_case_comment_endpoint(
712 return {"message": "Case comment deleted successfully", "success": True}
713
714
612 -@incidents_db_operations_router.get("/alert/available-users", response_model=AvailableUsersResponse)
715 +@incidents_db_operations_router.get(
716 + "/alert/available-users",
717 + response_model=AvailableUsersResponse,
718 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
719 +)
720 async def get_available_users(db: AsyncSession = Depends(get_db)):
721 all_users = await select_all_users()
722 return AvailableUsersResponse(
@@ -619,7 +726,11 @@ async def get_available_users(db: AsyncSession = Depends(get_db)):
726 )
727
728
622 -@incidents_db_operations_router.put("/alert/assigned-to", response_model=AlertResponse)
729 +@incidents_db_operations_router.put(
730 + "/alert/assigned-to",
731 + response_model=AlertResponse,
732 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
733 +)
734 async def update_assigned_to_endpoint(assigned_to: AssignedToAlert, db: AsyncSession = Depends(get_db)):
735 all_users = await select_all_users()
736 user_names = [user.username for user in all_users]
@@ -632,7 +743,11 @@ async def update_assigned_to_endpoint(assigned_to: AssignedToAlert, db: AsyncSes
743 )
744
745
635 -@incidents_db_operations_router.post("/alert/context", response_model=AlertContextResponse)
746 +@incidents_db_operations_router.post(
747 + "/alert/context",
748 + response_model=AlertContextResponse,
749 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
750 +)
751 async def create_alert_context_endpoint(alert_context: AlertContextCreate, db: AsyncSession = Depends(get_db)):
752 return AlertContextResponse(
753 alert_context=await create_alert_context(alert_context, db),
@@ -641,7 +756,11 @@ async def create_alert_context_endpoint(alert_context: AlertContextCreate, db: A
756 )
757
758
644 -@incidents_db_operations_router.get("/alert/context/{alert_context_id}", response_model=AlertContextResponse)
759 +@incidents_db_operations_router.get(
760 + "/alert/context/{alert_context_id}",
761 + response_model=AlertContextResponse,
762 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
763 +)
764 async def get_alert_context_by_id_endpoint(alert_context_id: int, db: AsyncSession = Depends(get_db)):
765 return AlertContextResponse(
766 alert_context=await get_alert_context_by_id(alert_context_id, db),
@@ -650,17 +769,29 @@ async def get_alert_context_by_id_endpoint(alert_context_id: int, db: AsyncSessi
769 )
770
771
653 -@incidents_db_operations_router.post("/alert/asset", response_model=AssetResponse)
772 +@incidents_db_operations_router.post(
773 + "/alert/asset",
774 + response_model=AssetResponse,
775 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
776 +)
777 async def create_asset_endpoint(asset: AssetCreate, db: AsyncSession = Depends(get_db)):
778 return AssetResponse(asset=await create_asset(asset, db), success=True, message="Asset created successfully")
779
780
658 -@incidents_db_operations_router.post("/alert/ioc", response_model=AlertIoCResponse)
781 +@incidents_db_operations_router.post(
782 + "/alert/ioc",
783 + response_model=AlertIoCResponse,
784 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
785 +)
786 async def create_alert_ioc_endpoint(ioc: AlertIoCCreate, db: AsyncSession = Depends(get_db)):
787 return AlertIoCResponse(alert_ioc=await create_alert_ioc(ioc, db), success=True, message="Alert IoC created successfully")
788
789
663 -@incidents_db_operations_router.get("/alert/ioc/{ioc_value}", response_model=AlertOutResponse)
790 +@incidents_db_operations_router.get(
791 + "/alert/ioc/{ioc_value}",
792 + response_model=AlertOutResponse,
793 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
794 +)
795 async def list_alerts_by_ioc_value_endpoint(
796 ioc_value: str,
797 page: int = Query(1, ge=1),
@@ -707,7 +838,11 @@ async def list_alerts_by_ioc_value_endpoint(
838 )
839
840
710 -@incidents_db_operations_router.delete("/alert/ioc", response_model=AlertIoCResponse)
841 +@incidents_db_operations_router.delete(
842 + "/alert/ioc",
843 + response_model=AlertIoCResponse,
844 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
845 +)
846 async def delete_alert_ioc_endpoint(ioc: AlertIoCDelete, db: AsyncSession = Depends(get_db)):
847 return AlertIoCResponse(
848 alert_ioc=await delete_alert_ioc(ioc=ioc, db=db),
@@ -716,12 +851,20 @@ async def delete_alert_ioc_endpoint(ioc: AlertIoCDelete, db: AsyncSession = Depe
851 )
852
853
719 -@incidents_db_operations_router.post("/alert/tag", response_model=AlertTagResponse)
854 +@incidents_db_operations_router.post(
855 + "/alert/tag",
856 + response_model=AlertTagResponse,
857 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
858 +)
859 async def create_alert_tag_endpoint(alert_tag: AlertTagCreate, db: AsyncSession = Depends(get_db)):
860 return AlertTagResponse(alert_tag=await create_alert_tag(alert_tag, db), success=True, message="Alert tag created successfully")
861
862
724 -@incidents_db_operations_router.get("/alert/tag/{tag}", response_model=AlertOutResponse)
863 +@incidents_db_operations_router.get(
864 + "/alert/tag/{tag}",
865 + response_model=AlertOutResponse,
866 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
867 +)
868 async def list_alerts_by_tag_endpoint(
869 tag: str,
870 page: int = Query(1, ge=1),
@@ -768,7 +911,11 @@ async def list_alerts_by_tag_endpoint(
911 )
912
913
771 -@incidents_db_operations_router.delete("/alert/tag", response_model=AlertTagResponse)
914 +@incidents_db_operations_router.delete(
915 + "/alert/tag",
916 + response_model=AlertTagResponse,
917 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
918 +)
919 async def delete_alert_tag_endpoint(alert_tag: AlertTagDelete, db: AsyncSession = Depends(get_db)):
920 return AlertTagResponse(
921 alert_tag=await delete_alert_tag(alert_tag.alert_id, alert_tag.tag_id, db),
@@ -777,12 +924,20 @@ async def delete_alert_tag_endpoint(alert_tag: AlertTagDelete, db: AsyncSession
924 )
925
926
780 -@incidents_db_operations_router.post("/case/create", response_model=CaseResponse)
927 +@incidents_db_operations_router.post(
928 + "/case/create",
929 + response_model=CaseResponse,
930 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
931 +)
932 async def create_case_endpoint(case: CaseCreate, db: AsyncSession = Depends(get_db)):
933 return CaseResponse(case=await create_case(case, db), success=True, message="Case created successfully")
934
935
785 -@incidents_db_operations_router.post("/case/alert-link", response_model=CaseAlertLinkResponse)
936 +@incidents_db_operations_router.post(
937 + "/case/alert-link",
938 + response_model=CaseAlertLinkResponse,
939 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
940 +)
941 async def create_case_alert_link_endpoint(case_alert_link: CaseAlertLinkCreate, db: AsyncSession = Depends(get_db)):
942 return CaseAlertLinkResponse(
943 case_alert_link=await create_case_alert_link(case_alert_link, db),
@@ -791,7 +946,11 @@ async def create_case_alert_link_endpoint(case_alert_link: CaseAlertLinkCreate,
946 )
947
948
794 -@incidents_db_operations_router.post("/case/alert-links", response_model=CaseAlertLinksResponse)
949 +@incidents_db_operations_router.post(
950 + "/case/alert-links",
951 + response_model=CaseAlertLinksResponse,
952 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
953 +)
954 async def create_case_alert_links_endpoint(case_alert_links: CaseAlertLinksCreate, db: AsyncSession = Depends(get_db)):
955 return CaseAlertLinksResponse(
956 case_alert_links=await create_case_alert_links_bulk(case_alert_links, db),
@@ -800,12 +959,20 @@ async def create_case_alert_links_endpoint(case_alert_links: CaseAlertLinksCreat
959 )
960
961
803 -@incidents_db_operations_router.post("/case/alert-unlink", response_model=CaseAlertUnLinkResponse)
962 +@incidents_db_operations_router.post(
963 + "/case/alert-unlink",
964 + response_model=CaseAlertUnLinkResponse,
965 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
966 +)
967 async def case_alert_unlink_endpoint(case_alert_link: CaseAlertUnLink, db: AsyncSession = Depends(get_db)):
968 return await case_alert_unlink(case_alert_link, db)
969
970
808 -@incidents_db_operations_router.post("/case/from-alert", response_model=CaseAlertLinkResponse)
971 +@incidents_db_operations_router.post(
972 + "/case/from-alert",
973 + response_model=CaseAlertLinkResponse,
974 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
975 +)
976 async def create_case_from_alert_endpoint(alert_id: CaseCreateFromAlert, db: AsyncSession = Depends(get_db)):
977 case = await create_case_from_alert(alert_id.alert_id, db)
978 if case is None:
@@ -817,7 +984,11 @@ async def create_case_from_alert_endpoint(alert_id: CaseCreateFromAlert, db: Asy
984 )
985
986
820 -@incidents_db_operations_router.get("/alerts/filter-options", response_model=AlertFilterOptionsResponse)
987 +@incidents_db_operations_router.get(
988 + "/alerts/filter-options",
989 + response_model=AlertFilterOptionsResponse,
990 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
991 +)
992 async def get_alert_filter_options_endpoint(
993 current_user: User = Depends(AuthHandler().get_current_user),
994 db: AsyncSession = Depends(get_db),
@@ -833,7 +1004,11 @@ async def get_alert_filter_options_endpoint(
1004 )
1005
1006
836 -@incidents_db_operations_router.get("/cases/filter-options", response_model=CaseFilterOptionsResponse)
1007 +@incidents_db_operations_router.get(
1008 + "/cases/filter-options",
1009 + response_model=CaseFilterOptionsResponse,
1010 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1011 +)
1012 async def get_case_filter_options_endpoint(
1013 current_user: User = Depends(AuthHandler().get_current_user),
1014 db: AsyncSession = Depends(get_db),
@@ -865,7 +1040,11 @@ async def get_case_filter_options_endpoint(
1040 )
1041
1042
868 -@incidents_db_operations_router.get("/alerts", response_model=AlertOutResponse)
1043 +@incidents_db_operations_router.get(
1044 + "/alerts",
1045 + response_model=AlertOutResponse,
1046 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1047 +)
1048 async def list_alerts_endpoint(
1049 page: int = Query(1, ge=1),
1050 page_size: int = Query(25, ge=1),
@@ -895,7 +1074,11 @@ async def list_alerts_endpoint(
1074 )
1075
1076
898 -@incidents_db_operations_router.get("/alert/{alert_id}", response_model=AlertOutResponse)
1077 +@incidents_db_operations_router.get(
1078 + "/alert/{alert_id}",
1079 + response_model=AlertOutResponse,
1080 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1081 +)
1082 async def get_alert_by_id_endpoint(
1083 alert_id: int,
1084 current_user: User = Depends(AuthHandler().get_current_user),
@@ -914,7 +1097,10 @@ async def get_alert_by_id_endpoint(
1097 return AlertOutResponse(alerts=[alert], success=True, message="Alert retrieved successfully")
1098
1099
917 -@incidents_db_operations_router.delete("/alert/{alert_id}")
1100 +@incidents_db_operations_router.delete(
1101 + "/alert/{alert_id}",
1102 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1103 +)
1104 async def delete_alert_endpoint(
1105 alert_id: int,
1106 current_user: User = Depends(AuthHandler().get_current_user),
@@ -935,7 +1121,11 @@ async def delete_alert_endpoint(
1121 return {"message": "Alert deleted successfully", "success": True}
1122
1123
938 -@incidents_db_operations_router.delete("/alerts", response_model=DeleteAlertsResponse)
1124 +@incidents_db_operations_router.delete(
1125 + "/alerts",
1126 + response_model=DeleteAlertsResponse,
1127 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1128 +)
1129 async def delete_alerts_endpoint(request: DeleteAlertsRequest, db: AsyncSession = Depends(get_db)):
1130 """
1131 Endpoint to delete alerts.
@@ -973,7 +1163,11 @@ async def delete_alerts_endpoint(request: DeleteAlertsRequest, db: AsyncSession
1163 )
1164
1165
976 -@incidents_db_operations_router.delete("/alerts/by-title/{title_filter}", response_model=DeleteAlertsResponse)
1166 +@incidents_db_operations_router.delete(
1167 + "/alerts/by-title/{title_filter}",
1168 + response_model=DeleteAlertsResponse,
1169 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1170 +)
1171 async def delete_alerts_by_title_endpoint(
1172 title_filter: str,
1173 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1041,7 +1235,11 @@ async def delete_alerts_by_title_endpoint(
1235 )
1236
1237
1044 -@incidents_db_operations_router.get("/alerts/status/{status}", response_model=AlertOutResponse)
1238 +@incidents_db_operations_router.get(
1239 + "/alerts/status/{status}",
1240 + response_model=AlertOutResponse,
1241 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1242 +)
1243 async def list_alerts_by_status_endpoint(
1244 status: AlertStatus,
1245 page: int = Query(1, ge=1),
@@ -1094,7 +1292,11 @@ async def list_alerts_by_status_endpoint(
1292 )
1293
1294
1097 -@incidents_db_operations_router.get("/alerts/assigned-to/{assigned_to}", response_model=AlertOutResponse)
1295 +@incidents_db_operations_router.get(
1296 + "/alerts/assigned-to/{assigned_to}",
1297 + response_model=AlertOutResponse,
1298 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1299 +)
1300 async def list_alerts_by_assigned_to_endpoint(
1301 assigned_to: str,
1302 page: int = Query(1, ge=1),
@@ -1142,7 +1344,11 @@ async def list_alerts_by_assigned_to_endpoint(
1344 )
1345
1346
1145 -@incidents_db_operations_router.get("/alerts/asset/{asset_name}", response_model=AlertOutResponse)
1347 +@incidents_db_operations_router.get(
1348 + "/alerts/asset/{asset_name}",
1349 + response_model=AlertOutResponse,
1350 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1351 +)
1352 async def list_alerts_by_asset_name_endpoint(
1353 asset_name: str,
1354 page: int = Query(1, ge=1),
@@ -1190,7 +1396,11 @@ async def list_alerts_by_asset_name_endpoint(
1396 )
1397
1398
1193 -@incidents_db_operations_router.get("/alerts/title/{title}", response_model=AlertOutResponse)
1399 +@incidents_db_operations_router.get(
1400 + "/alerts/title/{title}",
1401 + response_model=AlertOutResponse,
1402 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1403 +)
1404 async def list_alerts_by_title_endpoint(
1405 title: str,
1406 page: int = Query(1, ge=1),
@@ -1238,7 +1448,11 @@ async def list_alerts_by_title_endpoint(
1448 )
1449
1450
1241 -@incidents_db_operations_router.get("/alerts/customer/{customer_code}", response_model=AlertOutResponse)
1451 +@incidents_db_operations_router.get(
1452 + "/alerts/customer/{customer_code}",
1453 + response_model=AlertOutResponse,
1454 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1455 +)
1456 async def list_alerts_by_customer_code_endpoint(
1457 customer_code: str,
1458 page: int = Query(1, ge=1),
@@ -1263,7 +1477,11 @@ async def list_alerts_by_customer_code_endpoint(
1477 )
1478
1479
1266 -@incidents_db_operations_router.get("/alerts/source/{source}", response_model=AlertOutResponse)
1480 +@incidents_db_operations_router.get(
1481 + "/alerts/source/{source}",
1482 + response_model=AlertOutResponse,
1483 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1484 +)
1485 async def list_alerts_by_source_endpoint(
1486 source: str,
1487 page: int = Query(1, ge=1),
@@ -1311,7 +1529,11 @@ async def list_alerts_by_source_endpoint(
1529 )
1530
1531
1314 -@incidents_db_operations_router.get("/alerts/filter", response_model=AlertOutResponse)
1532 +@incidents_db_operations_router.get(
1533 + "/alerts/filter",
1534 + response_model=AlertOutResponse,
1535 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1536 +)
1537 async def list_alerts_multiple_filters_endpoint(
1538 assigned_to: Optional[str] = Query(None),
1539 alert_title: Optional[str] = Query(None),
@@ -1393,7 +1615,11 @@ async def list_alerts_multiple_filters_endpoint(
1615 )
1616
1617
1396 -@incidents_db_operations_router.get("/cases", response_model=CaseOutResponse)
1618 +@incidents_db_operations_router.get(
1619 + "/cases",
1620 + response_model=CaseOutResponse,
1621 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1622 +)
1623 async def list_cases_endpoint(
1624 page: int = Query(1, ge=1),
1625 page_size: int = Query(25, ge=1),
@@ -1422,7 +1648,11 @@ async def list_cases_endpoint(
1648 )
1649
1650
1425 -@incidents_db_operations_router.put("/case/status", response_model=CaseOutResponse)
1651 +@incidents_db_operations_router.put(
1652 + "/case/status",
1653 + response_model=CaseOutResponse,
1654 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1655 +)
1656 async def update_case_status_endpoint(
1657 case_status: UpdateCaseStatus,
1658 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1516,7 +1746,11 @@ async def update_case_status_endpoint(
1746 return CaseOutResponse(cases=[updated_case], success=True, message=message)
1747
1748
1519 -@incidents_db_operations_router.put("/case/escalated", response_model=CaseOutResponse)
1749 +@incidents_db_operations_router.put(
1750 + "/case/escalated",
1751 + response_model=CaseOutResponse,
1752 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1753 +)
1754 async def update_case_escalated_endpoint(
1755 escalate_case: EscalateCase,
1756 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1542,7 +1776,11 @@ async def update_case_escalated_endpoint(
1776 return CaseOutResponse(cases=[updated_case], success=True, message="Case escalated status updated successfully")
1777
1778
1545 -@incidents_db_operations_router.put("/case/assigned-to", response_model=CaseOutResponse)
1779 +@incidents_db_operations_router.put(
1780 + "/case/assigned-to",
1781 + response_model=CaseOutResponse,
1782 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1783 +)
1784 async def update_case_assigned_to_endpoint(
1785 assigned_to: AssignedToCase,
1786 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1575,7 +1813,11 @@ async def update_case_assigned_to_endpoint(
1813 )
1814
1815
1578 -@incidents_db_operations_router.put("/case/customer-code", response_model=CaseOutResponse)
1816 +@incidents_db_operations_router.put(
1817 + "/case/customer-code",
1818 + response_model=CaseOutResponse,
1819 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1820 +)
1821 async def update_case_customer_code_endpoint(
1822 case_id: int,
1823 customer_code: str,
@@ -1609,7 +1851,10 @@ async def update_case_customer_code_endpoint(
1851 )
1852
1853
1612 -@incidents_db_operations_router.delete("/case/{case_id}")
1854 +@incidents_db_operations_router.delete(
1855 + "/case/{case_id}",
1856 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1857 +)
1858 async def delete_case_endpoint(
1859 case_id: int,
1860 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1629,7 +1874,11 @@ async def delete_case_endpoint(
1874 return {"message": "Case deleted successfully", "success": True}
1875
1876
1632 -@incidents_db_operations_router.get("/case/status/{status}", response_model=CaseOutResponse)
1877 +@incidents_db_operations_router.get(
1878 + "/case/status/{status}",
1879 + response_model=CaseOutResponse,
1880 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1881 +)
1882 async def list_cases_by_status_endpoint(
1883 status: AlertStatus,
1884 page: int = Query(1, ge=1),
@@ -1671,7 +1920,11 @@ async def list_cases_by_status_endpoint(
1920 )
1921
1922
1674 -@incidents_db_operations_router.get("/case/assigned-to/{assigned_to}", response_model=CaseOutResponse)
1923 +@incidents_db_operations_router.get(
1924 + "/case/assigned-to/{assigned_to}",
1925 + response_model=CaseOutResponse,
1926 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1927 +)
1928 async def list_cases_by_assigned_to_endpoint(
1929 assigned_to: str,
1930 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1694,7 +1947,11 @@ async def list_cases_by_assigned_to_endpoint(
1947 return CaseOutResponse(cases=cases, success=True, message="Cases retrieved successfully")
1948
1949
1697 -@incidents_db_operations_router.get("/case/asset/{asset_name}", response_model=CaseOutResponse)
1950 +@incidents_db_operations_router.get(
1951 + "/case/asset/{asset_name}",
1952 + response_model=CaseOutResponse,
1953 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1954 +)
1955 async def list_cases_by_asset_name_endpoint(
1956 asset_name: str,
1957 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1723,7 +1980,11 @@ async def list_cases_by_asset_name_endpoint(
1980 return CaseOutResponse(cases=cases, success=True, message="Cases retrieved successfully")
1981
1982
1726 -@incidents_db_operations_router.get("/case/customer/{customer_code}", response_model=CaseOutResponse)
1983 +@incidents_db_operations_router.get(
1984 + "/case/customer/{customer_code}",
1985 + response_model=CaseOutResponse,
1986 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
1987 +)
1988 async def list_cases_by_customer_code_endpoint(
1989 customer_code: str,
1990 current_user: User = Depends(customer_access_handler.require_customer_access()),
@@ -1739,13 +2000,21 @@ async def list_cases_by_customer_code_endpoint(
2000 return CaseOutResponse(cases=await list_cases_by_customer_code(customer_code, db), success=True, message="Cases retrieved successfully")
2001
2002
1742 -@incidents_db_operations_router.get("/case/data-store", response_model=ListCaseDataStoreResponse)
2003 +@incidents_db_operations_router.get(
2004 + "/case/data-store",
2005 + response_model=ListCaseDataStoreResponse,
2006 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2007 +)
2008 async def list_all_case_data_store_files_endpoint(db: AsyncSession = Depends(get_db)):
2009 logger.info("Listing all files in the data store")
2010 return ListCaseDataStoreResponse(case_data_store=await list_all_files(db), success=True, message="Files retrieved successfully")
2011
2012
1748 -@incidents_db_operations_router.get("/case/data-store/{case_id}", response_model=ListCaseDataStoreResponse)
2013 +@incidents_db_operations_router.get(
2014 + "/case/data-store/{case_id}",
2015 + response_model=ListCaseDataStoreResponse,
2016 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2017 +)
2018 async def list_case_data_store_files_endpoint(
2019 case_id: int,
2020 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1768,7 +2037,10 @@ async def list_case_data_store_files_endpoint(
2037 )
2038
2039
1771 -@incidents_db_operations_router.get("/case/data-store/download/{case_id}/{file_name}")
2040 +@incidents_db_operations_router.get(
2041 + "/case/data-store/download/{case_id}/{file_name}",
2042 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2043 +)
2044 async def download_case_data_store_file_endpoint(
2045 case_id: int,
2046 file_name: str,
@@ -1793,7 +2065,11 @@ async def download_case_data_store_file_endpoint(
2065 return StreamingResponse(output, media_type=file_content_type, headers={"Content-Disposition": f"attachment; filename={file_name}"})
2066
2067
1796 -@incidents_db_operations_router.post("/case/data-store/upload", response_model=CaseDataStoreResponse)
2068 +@incidents_db_operations_router.post(
2069 + "/case/data-store/upload",
2070 + response_model=CaseDataStoreResponse,
2071 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2072 +)
2073 async def upload_case_data_store_endpoint(
2074 case_id: int,
2075 file: UploadFile = File(...),
@@ -1820,7 +2096,10 @@ async def upload_case_data_store_endpoint(
2096 )
2097
2098
1823 -@incidents_db_operations_router.delete("/case/data-store/{case_id}/{file_name}")
2099 +@incidents_db_operations_router.delete(
2100 + "/case/data-store/{case_id}/{file_name}",
2101 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2102 +)
2103 async def delete_case_data_store_file_endpoint(
2104 case_id: int,
2105 file_name: str,
@@ -1841,7 +2120,11 @@ async def delete_case_data_store_file_endpoint(
2120 return {"message": "File deleted successfully", "success": True}
2121
2122
1844 -@incidents_db_operations_router.get("/case/{case_id}", response_model=CaseOutResponse)
2123 +@incidents_db_operations_router.get(
2124 + "/case/{case_id}",
2125 + response_model=CaseOutResponse,
2126 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2127 +)
2128 async def get_case_by_id_endpoint(
2129 case_id: int,
2130 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1860,7 +2143,11 @@ async def get_case_by_id_endpoint(
2143 return CaseOutResponse(cases=[case], success=True, message="Case retrieved successfully")
2144
2145
1863 -@incidents_db_operations_router.post("/case/notification", response_model=CaseNotificationResponse)
2146 +@incidents_db_operations_router.post(
2147 + "/case/notification",
2148 + response_model=CaseNotificationResponse,
2149 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2150 +)
2151 async def create_case_notification_endpoint(
2152 request: CaseNotificationCreate,
2153 current_user: User = Depends(AuthHandler().get_current_user),
@@ -1914,7 +2201,11 @@ async def create_case_notification_endpoint(
2201 return CaseNotificationResponse(success=True, message="Case notification created successfully")
2202
2203
1917 -@incidents_db_operations_router.get("/case-report-template", response_model=CaseReportTemplateDataStoreListResponse)
2204 +@incidents_db_operations_router.get(
2205 + "/case-report-template",
2206 + response_model=CaseReportTemplateDataStoreListResponse,
2207 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2208 +)
2209 async def list_case_report_template_data_store_files_endpoint(db: AsyncSession = Depends(get_db)):
2210 logger.info("Listing all files in the data store")
2211 return CaseReportTemplateDataStoreListResponse(
@@ -1924,7 +2215,10 @@ async def list_case_report_template_data_store_files_endpoint(db: AsyncSession =
2215 )
2216
2217
1927 -@incidents_db_operations_router.get("/case-report-template/do-default-template-exists")
2218 +@incidents_db_operations_router.get(
2219 + "/case-report-template/do-default-template-exists",
2220 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2221 +)
2222 async def check_default_case_report_template_exists_endpoint(db: AsyncSession = Depends(get_db)):
2223 """
2224 Endpoint to check if any of the default case report template files exist in the data store.
@@ -1943,7 +2237,11 @@ async def check_default_case_report_template_exists_endpoint(db: AsyncSession =
2237 return {"success": True, "message": "No default case report templates exist", "default_template_exists": False}
2238
2239
1946 -@incidents_db_operations_router.post("/case-report-template/default-template", response_model=CaseReportTemplateDataStoreListResponse)
2240 +@incidents_db_operations_router.post(
2241 + "/case-report-template/default-template",
2242 + response_model=CaseReportTemplateDataStoreListResponse,
2243 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2244 +)
2245 async def create_default_case_report_template_endpoint(db: AsyncSession = Depends(get_db)):
2246 """
2247 Create a default case report template in the data store.
@@ -1962,7 +2260,10 @@ async def create_default_case_report_template_endpoint(db: AsyncSession = Depend
2260 )
2261
2262
1965 -@incidents_db_operations_router.get("/case-report-template/download/{file_name}")
2263 +@incidents_db_operations_router.get(
2264 + "/case-report-template/download/{file_name}",
2265 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2266 +)
2267 async def download_case_report_template_endpoint(file_name: str, db: AsyncSession = Depends(get_db)) -> StreamingResponse:
2268 file_bytes, file_content_type = await download_report_template(file_name, db)
2269 logger.info(f"Streaming file {file_name}")
@@ -1972,7 +2273,11 @@ async def download_case_report_template_endpoint(file_name: str, db: AsyncSessio
2273 return StreamingResponse(output, media_type=file_content_type, headers={"Content-Disposition": f"attachment; filename={file_name}"})
2274
2275
1975 -@incidents_db_operations_router.post("/case-report-template/upload", response_model=CaseReportTemplateDataStoreResponse)
2276 +@incidents_db_operations_router.post(
2277 + "/case-report-template/upload",
2278 + response_model=CaseReportTemplateDataStoreResponse,
2279 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2280 +)
2281 async def upload_case_report_template_endpoint(
2282 file: UploadFile = File(...),
2283 db: AsyncSession = Depends(get_db),
@@ -1993,7 +2298,10 @@ async def upload_case_report_template_endpoint(
2298 )
2299
2300
1996 -@incidents_db_operations_router.delete("/case-report-template/{file_name}")
2301 +@incidents_db_operations_router.delete(
2302 + "/case-report-template/{file_name}",
2303 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
2304 +)
2305 async def delete_case_report_template_endpoint(file_name: str, db: AsyncSession = Depends(get_db)):
2306 await delete_report_template(file_name, db)
2307 return {"message": "File deleted successfully", "success": True}
backend/app/incidents/routes/incident_alert.py
+3
@@ -63,6 +63,7 @@ async def verify_velociraptor_header(velociraptor: str = Header(None)):
63 "/index/names",
64 response_model=IndexNamesResponse,
65 description="Get the Graylog event indices",
66 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
67 )
68 async def get_index_names_route() -> IndexNamesResponse:
69 """
@@ -91,6 +92,7 @@ async def get_alerts_not_created_route() -> AlertsPayload:
92 @incidents_alerts_router.post(
93 "/alert/details",
94 description="Get the details of a single alert",
95 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
96 )
97 async def get_single_alert_details_route(
98 create_alert_request: CreateAlertRequestRoute,
@@ -117,6 +119,7 @@ async def get_single_alert_details_route(
119 @incidents_alerts_router.post(
120 "/alert/timeline",
121 description="Get the timeline of an alert",
122 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
123 )
124 async def get_alert_timeline_route(
125 alert: CreateAlertRequestRoute,
backend/app/incidents/routes/incident_report.py
+6
@@ -11,12 +11,14 @@ from fastapi import APIRouter
11 from fastapi import Depends
12 from fastapi import HTTPException
13 from fastapi import Query
14 +from fastapi import Security
15 from fastapi.responses import FileResponse
16 from fastapi.responses import StreamingResponse
17 from sqlalchemy.ext.asyncio import AsyncSession
18 from sqlalchemy.orm import selectinload
19 from sqlmodel import select
20
21 +from app.auth.routes.auth import AuthHandler
22 from app.customers.routes.customers import get_customer
23 from app.db.db_session import get_db
24 from app.incidents.models import Alert
@@ -178,6 +180,7 @@ def generate_csv_content(rows: List[Dict[str, Any]]) -> StringIO:
180 @incidents_report_router.post(
181 "/generate-report-csv",
182 description="Generate a report for all cases. Optionally filter by year and month.",
183 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
184 )
185 async def get_cases_export_all_route(
186 year: Optional[int] = Query(None, description="Filter by year (e.g. 2026)", ge=2000, le=2100),
@@ -199,6 +202,7 @@ async def get_cases_export_all_route(
202 @incidents_report_router.post(
203 "/generate-report-csv/{customer_code}",
204 description="Generate a report for a customer. Optionally filter by year and month.",
205 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
206 )
207 async def get_cases_export_customer_route(
208 customer_code: str,
@@ -222,6 +226,7 @@ async def get_cases_export_customer_route(
226 @incidents_report_router.post(
227 "/generate-report-docx",
228 description="Generate a docx report for a case.",
229 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
230 )
231 async def get_cases_export_docx_route(
232 request: CaseDownloadDocxRequest,
@@ -249,6 +254,7 @@ async def get_cases_export_docx_route(
254 @incidents_report_router.post(
255 "/generate-report-pdf",
256 description="Generate a PDF report for a case.",
257 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
258 )
259 async def get_cases_export_pdf_route(
260 request: CaseDownloadDocxRequest,
backend/app/integrations/cato/routes/provision.py
+3
@@ -1,7 +1,9 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from sqlalchemy.ext.asyncio import AsyncSession
5
6 +from app.auth.routes.auth import AuthHandler
7 from app.db.db_session import get_db
8 from app.integrations.cato.schema.provision import ProvisionCatoRequest
9 from app.integrations.cato.schema.provision import ProvisionCatoResponse
@@ -17,6 +19,7 @@ integration_cato_provision_scheduler_router = APIRouter()
19 "/provision",
20 response_model=ProvisionCatoResponse,
21 description="Provision a Cato integration.",
22 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
23 )
24 async def provision_Cato_route(
25 provision_cato_request: ProvisionCatoRequest,
backend/app/integrations/copilot_searches/routes/copilot_searches.py
+15
@@ -3,7 +3,9 @@ from typing import Optional
3 from fastapi import APIRouter
4 from fastapi import HTTPException
5 from fastapi import Query
6 +from fastapi import Security
7
8 +from app.auth.routes.auth import AuthHandler
9 from app.connectors.graylog.routes.events import get_all_event_definitions
10 from app.connectors.graylog.schema.events import GraylogEventDefinitionsResponse
11 from app.integrations.copilot_searches.schema.copilot_searches import (
@@ -90,6 +92,7 @@ async def check_if_event_definition_exists(event_definition_title: str) -> bool:
92 "",
93 response_model=RuleListResponse,
94 description="List all detection rules with optional filtering",
95 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
96 )
97 async def list_rules(
98 platform: PlatformFilter = Query(
@@ -148,6 +151,7 @@ async def list_rules(
151 "/linux",
152 response_model=RuleListResponse,
153 description="List all Linux detection rules",
154 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
155 )
156 async def list_linux_rules(
157 status: Optional[RuleStatus] = Query(None),
@@ -177,6 +181,7 @@ async def list_linux_rules(
181 "/windows",
182 response_model=RuleListResponse,
183 description="List all Windows detection rules",
184 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
185 )
186 async def list_windows_rules(
187 status: Optional[RuleStatus] = Query(None),
@@ -206,6 +211,7 @@ async def list_windows_rules(
211 "/powershell",
212 response_model=RuleListResponse,
213 description="List all PowerShell detection rules",
214 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
215 )
216 async def list_powershell_rules(
217 status: Optional[RuleStatus] = Query(None),
@@ -235,6 +241,7 @@ async def list_powershell_rules(
241 "/cve",
242 response_model=RuleListResponse,
243 description="List all detection rules that have CVE tags",
244 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
245 )
246 async def list_cve_rules(
247 status: Optional[RuleStatus] = Query(None),
@@ -267,6 +274,7 @@ async def list_cve_rules(
274 "/stats",
275 response_model=RuleStatsResponse,
276 description="Get statistics about loaded detection rules",
277 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
278 )
279 async def get_rule_stats():
280 """Get statistics about loaded detection rules."""
@@ -279,6 +287,7 @@ async def get_rule_stats():
287 "/id/{rule_id}",
288 response_model=RuleDetailResponse,
289 description="Get full details of a specific rule by its ID",
290 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
291 )
292 async def get_rule_by_id_endpoint(rule_id: str):
293 """
@@ -301,6 +310,7 @@ async def get_rule_by_id_endpoint(rule_id: str):
310 "/name/{rule_name:path}",
311 response_model=RuleDetailResponse,
312 description="Get full details of a specific rule by its name",
313 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
314 )
315 async def get_rule_by_name_endpoint(rule_name: str):
316 """
@@ -328,6 +338,7 @@ async def get_rule_by_name_endpoint(rule_name: str):
338 "/mitre/{technique_id}",
339 response_model=RuleListResponse,
340 description="Get all rules that detect a specific MITRE ATT&CK technique",
341 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
342 )
343 async def get_rules_by_mitre(
344 technique_id: str,
@@ -353,6 +364,7 @@ async def get_rules_by_mitre(
364 "/refresh",
365 response_model=RefreshResponse,
366 description="Manually refresh the rules cache from GitHub",
367 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
368 )
369 async def refresh_rules():
370 """
@@ -374,6 +386,7 @@ async def refresh_rules():
386 "/execute",
387 response_model=ExecuteSearchResponse,
388 description="Execute a detection rule search against the Wazuh indexer",
389 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst", "customer_user"))],
390 )
391 async def execute_search(request: ExecuteSearchRequest):
392 """
@@ -424,6 +437,7 @@ async def execute_search(request: ExecuteSearchRequest):
437 "/graylog",
438 response_model=GraylogQueryResponse,
439 description="Generate a Graylog query from a rule with parameter substitution",
440 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
441 )
442 async def generate_graylog_query_endpoint(request: ExecuteGraylogQueryRequest):
443 """
@@ -479,6 +493,7 @@ async def generate_graylog_query_endpoint(request: ExecuteGraylogQueryRequest):
493 "/provision/graylog",
494 response_model=ProvisionGraylogAlertResponse,
495 description="Provision a Graylog event definition from a CoPilot Search rule",
496 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
497 )
498 async def provision_graylog_alert(request: ProvisionGraylogAlertRequest):
499 """
backend/app/integrations/darktrace/routes/provision.py
+3
@@ -1,7 +1,9 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from sqlalchemy.ext.asyncio import AsyncSession
5
6 +from app.auth.routes.auth import AuthHandler
7 from app.db.db_session import get_db
8 from app.integrations.darktrace.schema.provision import ProvisionDarktraceRequest
9 from app.integrations.darktrace.schema.provision import ProvisionDarktraceResponse
@@ -17,6 +19,7 @@ integration_darktrace_provision_router = APIRouter()
19 "/provision",
20 response_model=ProvisionDarktraceResponse,
21 description="Provision a Darktrace integration.",
22 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
23 )
24 async def provision_darktrace_route(
25 provision_darktrace_request: ProvisionDarktraceRequest,
backend/app/integrations/duo/routes/provision.py
+3
@@ -1,7 +1,9 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from sqlalchemy.ext.asyncio import AsyncSession
5
6 +from app.auth.routes.auth import AuthHandler
7 from app.db.db_session import get_db
8 from app.integrations.duo.schema.provision import ProvisionDuoRequest
9 from app.integrations.duo.schema.provision import ProvisionDuoResponse
@@ -17,6 +19,7 @@ integration_duo_provision_router = APIRouter()
19 "/provision",
20 response_model=ProvisionDuoResponse,
21 description="Provision a Duo integration.",
22 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
23 )
24 async def provision_duo_route(
25 provision_duo_request: ProvisionDuoRequest,
backend/app/integrations/huntress/routes/provision.py
+3
@@ -1,7 +1,9 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from sqlalchemy.ext.asyncio import AsyncSession
5
6 +from app.auth.routes.auth import AuthHandler
7 from app.db.db_session import get_db
8 from app.integrations.huntress.schema.provision import ProvisionHuntressRequest
9 from app.integrations.huntress.schema.provision import ProvisionHuntressResponse
@@ -17,6 +19,7 @@ integration_huntress_provision_scheduler_router = APIRouter()
19 "/provision",
20 response_model=ProvisionHuntressResponse,
21 description="Provision a Huntress integration.",
22 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
23 )
24 async def provision_huntress_route(
25 provision_huntress_request: ProvisionHuntressRequest,
backend/app/integrations/microsoft_patch_tuesday/routes/microsoft_patch_tuesday.py
+8
@@ -3,8 +3,10 @@ from typing import Optional
3
4 from fastapi import APIRouter
5 from fastapi import Query
6 +from fastapi import Security
7 from loguru import logger
8
9 +from app.auth.routes.auth import AuthHandler
10 from app.integrations.microsoft_patch_tuesday.schema.microsoft_patch_tuesday import (
11 AvailableCyclesResponse,
12 )
@@ -37,6 +39,7 @@ microsoft_patch_tuesday_router = APIRouter()
39 "",
40 response_model=PatchTuesdayResponse,
41 description="Get full Patch Tuesday data for a specific cycle",
42 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
43 )
44 async def get_patch_tuesday_data(
45 cycle: Optional[str] = Query(
@@ -78,6 +81,7 @@ async def get_patch_tuesday_data(
81 "/summary",
82 response_model=PatchTuesdaySummaryResponse,
83 description="Get Patch Tuesday summary with top prioritized items",
84 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
85 )
86 async def get_patch_tuesday_summary_endpoint(
87 cycle: Optional[str] = Query(
@@ -110,6 +114,7 @@ async def get_patch_tuesday_summary_endpoint(
114 "/cycles",
115 response_model=AvailableCyclesResponse,
116 description="Get available Patch Tuesday cycles",
117 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
118 )
119 async def get_cycles() -> AvailableCyclesResponse:
120 """
@@ -126,6 +131,7 @@ async def get_cycles() -> AvailableCyclesResponse:
131 "/search",
132 response_model=PatchTuesdayResponse,
133 description="Search for specific CVEs in Patch Tuesday data",
134 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
135 )
136 async def search_cves(
137 cve_ids: List[str] = Query(..., description="List of CVE IDs to search for"),
@@ -149,6 +155,7 @@ async def search_cves(
155 "/priority/{priority_level}",
156 response_model=PatchTuesdayResponse,
157 description="Get vulnerabilities by priority level",
158 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
159 )
160 async def get_by_priority(
161 priority_level: str,
@@ -232,6 +239,7 @@ async def get_by_priority(
239 "/kev",
240 response_model=PatchTuesdayResponse,
241 description="Get only CISA KEV (Known Exploited Vulnerabilities) items",
242 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
243 )
244 async def get_kev_items(
245 cycle: Optional[str] = Query(
backend/app/integrations/mimecast/routes/mimecast.py
+1
@@ -69,6 +69,7 @@ async def invoke_mimecast_route(
69 response_model=MimecastResponse,
70 description="Pull down Mimecast TTP URLs for a given time range. "
71 "Link to docs: https://integrations.mimecast.com/documentation/endpoint-reference/logs-and-statistics/get-ttp-url-logs/ ",
72 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
73 )
74 async def mimecast_ttp_url_route(
75 mimecast_request: MimecastRequest,
backend/app/integrations/mimecast/routes/provision.py
+5
@@ -1,7 +1,9 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from sqlalchemy.ext.asyncio import AsyncSession
5
6 +from app.auth.routes.auth import AuthHandler
7 from app.db.db_session import get_db
8 from app.integrations.mimecast.schema.mimecast import MimecastScheduledResponse
9 from app.integrations.mimecast.schema.provision import ProvisionMimecastRequest
@@ -18,6 +20,7 @@ integration_mimecast_scheduler_router = APIRouter()
20 "/provision",
21 response_model=ProvisionMimecastResponse,
22 description="Provision a mimecast integration.",
23 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
24 )
25 async def provision_mimecast_route(
26 provision_mimecast_request: ProvisionMimecastRequest,
@@ -62,6 +65,7 @@ async def provision_mimecast_route(
65 @integration_mimecast_scheduler_router.post(
66 "/invoke/scheduler/siem",
67 description="Invoke a mimecast integration.",
68 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
69 )
70 async def invoke_mimecast_siem_schedule_create(
71 time_interval: int,
@@ -91,6 +95,7 @@ async def invoke_mimecast_siem_schedule_create(
95 @integration_mimecast_scheduler_router.post(
96 "/invoke/scheduler/ttp",
97 description="Invoke a mimecast integration.",
98 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
99 )
100 async def invoke_mimecast_ttp_schedule_create(
101 time_interval: int,
backend/app/integrations/modules/routes/carbonblack.py
+3
@@ -1,8 +1,10 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from loguru import logger
5 from sqlalchemy.ext.asyncio import AsyncSession
6
7 +from app.auth.routes.auth import AuthHandler
8 from app.db.db_session import get_db
9 from app.integrations.modules.schema.carbonblack import CarbonBlackAuthKeys
10 from app.integrations.modules.schema.carbonblack import CollectCarbonBlack
@@ -71,6 +73,7 @@ async def get_collect_carbonblack_data(carbonblack_request, session, auth_keys):
73 "",
74 response_model=InvokeCarbonBlackResponse,
75 description="Invoke the CarbonBlack module.",
76 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
77 )
78 async def collect_carbonblack_route(carbonblack_request: InvokeCarbonBlackRequest, session: AsyncSession = Depends(get_db)):
79 """Pull down CarbonBlack Events."""
backend/app/integrations/modules/routes/cato.py
+3
@@ -1,8 +1,10 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from loguru import logger
5 from sqlalchemy.ext.asyncio import AsyncSession
6
7 +from app.auth.routes.auth import AuthHandler
8 from app.db.db_session import get_db
9 from app.integrations.modules.schema.cato import CatoAuthKeys
10 from app.integrations.modules.schema.cato import CollectCato
@@ -61,6 +63,7 @@ async def get_collect_cato_data(cato_request, session, auth_keys):
63 "",
64 response_model=InvokeCatoResponse,
65 description="Invoke the cato module.",
66 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
67 )
68 async def collect_cato_route(cato_request: InvokeCatoRequest, session: AsyncSession = Depends(get_db)):
69 """Pull down cato Events."""
backend/app/integrations/modules/routes/darktrace.py
+3
@@ -1,8 +1,10 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from loguru import logger
5 from sqlalchemy.ext.asyncio import AsyncSession
6
7 +from app.auth.routes.auth import AuthHandler
8 from app.db.db_session import get_db
9 from app.integrations.modules.schema.darktrace import CollectDarktrace
10 from app.integrations.modules.schema.darktrace import DarktraceAuthKeys
@@ -62,6 +64,7 @@ async def get_collect_darktrace_data(darktrace_request, session, auth_keys):
64 "",
65 response_model=InvokeDarktraceResponse,
66 description="Invoke the Darktrace module.",
67 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
68 )
69 async def collect_darktrace_route(darktrace_request: InvokeDarktraceRequest, session: AsyncSession = Depends(get_db)):
70 """Pull down Darktrace Events."""
backend/app/integrations/modules/routes/duo.py
+3
@@ -1,8 +1,10 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from loguru import logger
5 from sqlalchemy.ext.asyncio import AsyncSession
6
7 +from app.auth.routes.auth import AuthHandler
8 from app.db.db_session import get_db
9 from app.integrations.modules.schema.duo import CollectDuo
10 from app.integrations.modules.schema.duo import DuoAuthKeys
@@ -62,6 +64,7 @@ async def get_collect_duo_data(duo_request, session, auth_keys):
64 "",
65 response_model=InvokeDuoResponse,
66 description="Invoke the Duo module.",
67 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
68 )
69 async def collect_duo_route(duo_request: InvokeDuoRequest, session: AsyncSession = Depends(get_db)):
70 """Pull down Duo Events."""
backend/app/integrations/modules/routes/huntress.py
+3
@@ -1,8 +1,10 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from loguru import logger
5 from sqlalchemy.ext.asyncio import AsyncSession
6
7 +from app.auth.routes.auth import AuthHandler
8 from app.db.db_session import get_db
9 from app.integrations.modules.schema.huntress import CollectHuntress
10 from app.integrations.modules.schema.huntress import HuntressAuthKeys
@@ -74,6 +76,7 @@ async def get_collect_huntress_data(huntress_request, session, auth_keys):
76 "",
77 response_model=InvokeHuntressResponse,
78 description="Invoke the Huntress module.",
79 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
80 )
81 async def collect_huntress_route(huntress_request: InvokeHuntressRequest, session: AsyncSession = Depends(get_db)):
82 """Pull down Huntress Events."""
backend/app/integrations/modules/routes/mimecast.py
+3
@@ -1,8 +1,10 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from loguru import logger
5 from sqlalchemy.ext.asyncio import AsyncSession
6
7 +from app.auth.routes.auth import AuthHandler
8 from app.db.db_session import get_db
9 from app.integrations.modules.schema.mimecast import CollectMimecast
10 from app.integrations.modules.schema.mimecast import InvokeMimecastRequest
@@ -65,6 +67,7 @@ async def get_collect_mimecast_data(mimecast_request, session, auth_keys):
67 "",
68 response_model=InvokeMimecastResponse,
69 description="Invoke the Huntress module.",
70 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
71 )
72 async def collect_huntress_route(mimecast_request: InvokeMimecastRequest, session: AsyncSession = Depends(get_db)):
73 """Pull down Huntress Events."""
backend/app/integrations/modules/routes/sap_siem.py
+10
@@ -1,8 +1,10 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from loguru import logger
5 from sqlalchemy.ext.asyncio import AsyncSession
6
7 +from app.auth.routes.auth import AuthHandler
8 from app.db.db_session import get_db
9 from app.integrations.modules.schema.sap_siem import CollectSapSiemRequest
10 from app.integrations.modules.schema.sap_siem import CustomerDetails
@@ -46,6 +48,7 @@ module_sap_siem_router = APIRouter()
48 "",
49 response_model=InvokeSAPSiemResponse,
50 description="Pull down SAP SIEM Events.",
51 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
52 )
53 async def collect_sap_siem_route(sap_siem_request: InvokeSapSiemRequest, session: AsyncSession = Depends(get_db)):
54 """Pull down SAP SIEM Events."""
@@ -126,6 +129,7 @@ async def collect_sap_siem_route(sap_siem_request: InvokeSapSiemRequest, session
129 "- Login attempts from different IP addresses, regardless of login status (at least 2 failed IP addresses)\n\n"
130 "- Successful login afterwards (from the third successful IP address)\n\n"
131 "Result: User compressed, IP addresses belong to an attack network",
132 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
133 )
134 async def invoke_sap_siem_successful_user_login_with_different_ip_route(
135 invoke_siem_analysis: InvokeSapSiemAnalysis,
@@ -150,6 +154,7 @@ async def invoke_sap_siem_successful_user_login_with_different_ip_route(
154 "Prerequisite: \n\n"
155 "- At least 3 failed login attempts with the same user name from 3 different IP addresses\n\n"
156 "Result: User compressed, IP addresses belong to an attack network",
157 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
158 )
159 async def invoke_sap_siem_same_user_failed_login_from_different_ip_route(
160 invoke_siem_analysis: InvokeSapSiemAnalysis,
@@ -174,6 +179,7 @@ async def invoke_sap_siem_same_user_failed_login_from_different_ip_route(
179 "Prerequisite: \n\n"
180 "- At least 3 failed login attempts with the same user name from at least two different GEO IP country locations\n\n"
181 "Result: User compressed, IP addresses belong to an attack network",
182 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
183 )
184 async def invoke_sap_siem_same_user_failed_login_from_different_geo_location_route(
185 invoke_siem_analysis: InvokeSapSiemAnalysis,
@@ -214,6 +220,7 @@ async def invoke_sap_siem_same_user_failed_login_from_different_geo_location_rou
220 "- At 12:10, another failed login attempt is made by `user2` from IP `5.5.5.5` also located in the US.\n"
221 "- At 12:15, a successful login attempt is made by `user2` from IP `6.6.6.6` located in the US.\n"
222 "- In this case, the function would not trigger a suspicious login for `user2` because all the login attempts are from the same country (US).",
223 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
224 )
225 async def invoke_sap_siem_same_user_successful_login_from_different_geo_location_route(
226 invoke_siem_analysis: InvokeSapSiemAnalysis,
@@ -238,6 +245,7 @@ async def invoke_sap_siem_same_user_successful_login_from_different_geo_location
245 "Prerequisite: \n\n"
246 "- At least 25 failed login attempts from different IP addresses\n\n"
247 "Result: IP addresses belong to an attack network",
248 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
249 )
250 async def invoke_sap_siem_brute_force_failed_logins_route(
251 invoke_siem_analysis: InvokeSapSiemAnalysis,
@@ -262,6 +270,7 @@ async def invoke_sap_siem_brute_force_failed_logins_route(
270 "Prerequisite: \n\n"
271 "- At least 10 different user name failed login attempts from the same IP address\n\n"
272 "Result: IP addresses belong to an attack network",
273 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
274 )
275 async def invoke_sap_siem_brute_force_failed_logins_same_ip_route(
276 invoke_siem_analysis: InvokeSapSiemAnalysis,
@@ -287,6 +296,7 @@ async def invoke_sap_siem_brute_force_failed_logins_same_ip_route(
296 "- At least 3 different user names that have failed from the same IP addressn\n"
297 "- At least one successful login from the same IP address after 3 different user names. \n\n"
298 "Result: User compromised, IP address belongs to an attack network",
299 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
300 )
301 async def invoke_sap_siem_successful_login_after_multiple_failed_logins_route(
302 invoke_siem_analysis: InvokeSapSiemAnalysis,
backend/app/integrations/monitoring_alert/routes/provision.py
+6
@@ -3,10 +3,12 @@ from typing import List
3 from fastapi import APIRouter
4 from fastapi import Depends
5 from fastapi import HTTPException
6 +from fastapi import Security
7 from loguru import logger
8 from sqlalchemy.ext.asyncio import AsyncSession
9 from sqlalchemy.future import select
10
11 +from app.auth.routes.auth import AuthHandler
12 from app.connectors.graylog.routes.events import get_all_event_definitions
13 from app.connectors.graylog.schema.events import GraylogEventDefinitionsResponse
14 from app.connectors.graylog.services.streams import get_streams
@@ -671,6 +673,7 @@ async def check_if_event_definition_exists(event_definition: str) -> bool:
673 "/available",
674 response_model=AvailableMonitoringAlertsResponse,
675 description="Get the available monitoring alerts.",
676 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
677 )
678 async def get_available_monitoring_alerts_route() -> AvailableMonitoringAlertsResponse:
679 """
@@ -688,6 +691,7 @@ async def get_available_monitoring_alerts_route() -> AvailableMonitoringAlertsRe
691 "/provision",
692 response_model=ProvisionWazuhMonitoringAlertResponse,
693 description="Provisions monitoring alerts.",
694 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
695 )
696 async def provision_monitoring_alert_route(
697 request: ProvisionMonitoringAlertRequest,
@@ -713,6 +717,7 @@ async def provision_monitoring_alert_route(
717 "/provision/custom",
718 response_model=ProvisionWazuhMonitoringAlertResponse,
719 description="Provisions custom monitoring alerts.",
720 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
721 )
722 async def provision_custom_monitoring_alert_route(
723 request: CustomMonitoringAlertProvisionModel,
@@ -743,6 +748,7 @@ async def provision_custom_monitoring_alert_route(
748 "/provision/testing",
749 response_model=ProvisionWazuhMonitoringAlertResponse,
750 description="Used for testing purposes. To test, upload a JSON document.",
751 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
752 )
753 async def provision_monitoring_alert_testing_route(
754 request: dict,
backend/app/integrations/nuclei/routes/nuclei.py
+22 -4
@@ -1,6 +1,8 @@
1 from fastapi import APIRouter
2 +from fastapi import Security
3 from loguru import logger
4
5 +from app.auth.routes.auth import AuthHandler
6 from app.integrations.nuclei.schema.nuclei import DeleteNucleiReportResponse
7 from app.integrations.nuclei.schema.nuclei import NucleiReportCollectionResponse
8 from app.integrations.nuclei.schema.nuclei import NucleiReportsAvailableResponse
@@ -14,19 +16,31 @@ from app.integrations.nuclei.services.nuclei import post_to_copilot_nuclei_modul
16 integration_nuclei_router = APIRouter()
17
18
17 -@integration_nuclei_router.get("/all_reports", response_model=NucleiReportsAvailableResponse)
19 +@integration_nuclei_router.get(
20 + "/all_reports",
21 + response_model=NucleiReportsAvailableResponse,
22 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
23 +)
24 async def get_all_reports():
25 logger.info("Collecting Nuclei Reports")
26 return await get_nuclei_reports_available()
27
28
23 -@integration_nuclei_router.get("/report/{host}/{report}", response_model=NucleiReportCollectionResponse)
29 +@integration_nuclei_router.get(
30 + "/report/{host}/{report}",
31 + response_model=NucleiReportCollectionResponse,
32 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
33 +)
34 async def get_report(host: str, report: str = "index.md"):
35 logger.info(f"Getting Nuclei Report for {host} and {report}")
36 return await get_nuclei_report(host, report)
37
38
29 -@integration_nuclei_router.post("/scan", response_model=NucleiScanResponse)
39 +@integration_nuclei_router.post(
40 + "/scan",
41 + response_model=NucleiScanResponse,
42 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
43 +)
44 async def post_test(
45 request: NucleiScanRequest,
46 ):
@@ -34,7 +48,11 @@ async def post_test(
48 return await post_to_copilot_nuclei_module(request)
49
50
37 -@integration_nuclei_router.delete("/delete_report/{host}", response_model=DeleteNucleiReportResponse)
51 +@integration_nuclei_router.delete(
52 + "/delete_report/{host}",
53 + response_model=DeleteNucleiReportResponse,
54 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
55 +)
56 async def delete_report(host: str):
57 logger.info(f"Deleting Nuclei Report for {host}")
58 return await delete_nuclei_report(host)
backend/app/integrations/routes.py
+2 -2
@@ -717,7 +717,7 @@ async def get_customer_integrations_meta_by_customer_code(
717 "/create_integration",
718 response_model=CustomerIntegrationCreateResponse,
719 description="Create a new customer integration.",
720 - # dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
720 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
721 )
722 async def create_integration(
723 customer_integration_create: CustomerIntegrationCreate,
@@ -789,7 +789,7 @@ async def create_integration(
789 "/create_integration_meta",
790 response_model=CustomerIntegrationsMetaResponse,
791 description="Create a new customer integration metadata.",
792 - # dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
792 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
793 )
794 async def create_integration_meta(
795 customer_integration_meta: CustomerIntegrationsMetaSchema,
backend/app/integrations/sap_siem/routes/provision.py
+3
@@ -1,7 +1,9 @@
1 from fastapi import APIRouter
2 from fastapi import Depends
3 +from fastapi import Security
4 from sqlalchemy.ext.asyncio import AsyncSession
5
6 +from app.auth.routes.auth import AuthHandler
7 from app.db.db_session import get_db
8 from app.integrations.sap_siem.schema.provision import ProvisionSapSiemRequest
9 from app.integrations.sap_siem.schema.provision import ProvisionSapSiemResponse
@@ -17,6 +19,7 @@ integration_sap_siem_provision_scheduler_router = APIRouter()
19 "/provision",
20 response_model=ProvisionSapSiemResponse,
21 description="Provision a SAP SIEM integration.",
22 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
23 )
24 async def provision_sap_siem_route(
25 provision_sap_siem_request: ProvisionSapSiemRequest,
backend/app/middleware/license.py
+14
@@ -11,6 +11,7 @@ import requests
11 from fastapi import APIRouter
12 from fastapi import Depends
13 from fastapi import HTTPException
14 +from fastapi import Security
15 from loguru import logger
16 from pydantic import BaseModel
17 from pydantic import Field
@@ -18,6 +19,7 @@ from sqlalchemy import delete
19 from sqlalchemy import select
20 from sqlalchemy.ext.asyncio import AsyncSession
21
22 +from app.auth.routes.auth import AuthHandler
23 from app.connectors.schema import UpdateConnector
24 from app.connectors.services import ConnectorServices
25 from app.db.db_session import get_db
@@ -650,6 +652,7 @@ async def send_get_request(endpoint: str) -> Dict[str, Any]:
652 "/subscription_features",
653 description="Get the subscription features available",
654 response_model=GetSubscriptionCatalogFeaturesResponse,
655 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
656 )
657 async def get_subscription_catalog():
658 """
@@ -690,6 +693,7 @@ async def get_subscription_catalog():
693 "/retrieve_license_by_email",
694 description="Retrieve a license by email",
695 response_model=GetLicenseResponse,
696 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
697 )
698 async def retrieve_license_by_email(request: GetLicenseByEmailRequest, session: AsyncSession = Depends(get_db)) -> GetLicenseResponse:
699 """
@@ -739,6 +743,7 @@ async def retrieve_license_by_email(request: GetLicenseByEmailRequest, session:
743 "/create_checkout_session",
744 description="Create a checkout session",
745 response_model=CheckoutSessionResponse,
746 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
747 )
748 async def create_checkout_session(request: FeatureSubscriptionRequest):
749 """
@@ -775,6 +780,7 @@ async def create_checkout_session(request: FeatureSubscriptionRequest):
780 "/trial_license",
781 description="Create a trial license",
782 response_model=TrialLicenseResponse,
783 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
784 )
785 async def create_trial_license_key(request: TrialLicenseRequest, session: AsyncSession = Depends(get_db)) -> TrialLicenseResponse:
786 """
@@ -826,6 +832,7 @@ async def create_trial_license_key(request: TrialLicenseRequest, session: AsyncS
832 "/cancel_subscription",
833 description="Cancel a subscription",
834 response_model=CancelSubscriptionResponse,
835 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
836 )
837 async def cancel_subscription(request: CancelSubscriptionRequest) -> CancelSubscriptionResponse:
838 results = await send_post_request(
@@ -850,6 +857,7 @@ async def cancel_subscription(request: CancelSubscriptionRequest) -> CancelSubsc
857 "/verify_license",
858 response_model=VerifyLicenseResponse,
859 description="Verify a license key",
860 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
861 )
862 async def verify_license_key(session: AsyncSession = Depends(get_db)) -> VerifyLicenseResponse:
863 license = await get_license(session)
@@ -918,6 +926,7 @@ async def verify_license_key(session: AsyncSession = Depends(get_db)) -> VerifyL
926 @license_router.get(
927 "/get_license",
928 description="Get a license",
929 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
930 )
931 async def get_license_key(session: AsyncSession = Depends(get_db)) -> GetLicenseResponse:
932 license = await get_license(session)
@@ -971,6 +980,7 @@ async def send_post_request(endpoint: str, data: Dict[str, Any] = None) -> Dict[
980 "/is_feature_enabled/{feature_name}",
981 response_model=IsFeatureEnabledResponse,
982 description="Check if a feature is enabled in a license",
983 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
984 )
985 async def is_feature_enabled_route(feature_name: str, session: AsyncSession = Depends(get_db)) -> IsFeatureEnabledResponse:
986 try:
@@ -994,6 +1004,7 @@ async def is_feature_enabled_route(feature_name: str, session: AsyncSession = De
1004 "/get_license_features",
1005 response_model=GetLicenseFeaturesResponse,
1006 description="Get license features",
1007 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
1008 )
1009 async def get_license_features(session: AsyncSession = Depends(get_db)) -> GetLicenseFeaturesResponse:
1010 license = await get_license(session)
@@ -1049,6 +1060,7 @@ async def get_license_features(session: AsyncSession = Depends(get_db)) -> GetLi
1060 @license_router.post(
1061 "/replace_license_in_db",
1062 description="Replace a license or create one if it doesn't exist",
1063 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
1064 )
1065 async def replace_license_in_db(request: ReplaceLicenseRequest, session: AsyncSession = Depends(get_db)):
1066 # Get license without raising error if it doesn't exist
@@ -1101,6 +1113,7 @@ async def replace_license_in_db(request: ReplaceLicenseRequest, session: AsyncSe
1113 "/retrieve-docker-compose",
1114 response_model=RetrieveDockerCompose,
1115 description="Retrieve Docker Compose for features enabled",
1116 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
1117 )
1118 async def retrieve_docker_compose(session: AsyncSession = Depends(get_db)) -> RetrieveDockerCompose:
1119 license = await get_license(session)
@@ -1121,6 +1134,7 @@ async def retrieve_docker_compose(session: AsyncSession = Depends(get_db)) -> Re
1134 @license_router.post(
1135 "/invalidate_cache",
1136 description="Manually invalidate license cache",
1137 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
1138 )
1139 async def invalidate_cache_route(session: AsyncSession = Depends(get_db)):
1140 """
backend/app/network_connectors/routes.py
+2 -2
@@ -651,7 +651,7 @@ async def get_customer_network_connectors_meta_by_customer_code(
651 "/create_network_connector",
652 response_model=CustomerNetworkConnectorsCreateResponse,
653 description="Create a new customer network_connector.",
654 - # dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
654 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
655 )
656 async def create_network_connector(
657 customer_network_connector_create: CustomerNetworkConnectorsCreate,
@@ -716,7 +716,7 @@ async def create_network_connector(
716 "/create_network_connector_meta",
717 response_model=CustomerNetworkConnectorsMetaResponse,
718 description="Create a new customer network_connector metadata.",
719 - # dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
719 + dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
720 )
721 async def create_network_connector_meta(
722 customer_network_connector_meta: CustomerNetworkConnectorsMetaSchema,
backend/app/version/services/version.py
+1 -1
@@ -7,7 +7,7 @@ from loguru import logger
7 from packaging.version import Version
8
9 # Current version - update this with each release
10 -CURRENT_VERSION = "0.1.58"
10 +CURRENT_VERSION = "0.1.59"
11 VERSION_CHECK_URL = "https://api.github.com/repos/socfortress/CoPilot/releases/latest"
12
13