88from os import environ
99
1010from src .execute import run_command
11- from src .types import RequestData
11+ from src .types import RequestData , ServiceJsonType , SwarmRequestData
1212
1313logging .basicConfig (level = logging .INFO )
1414
@@ -19,24 +19,33 @@ class ValidateRequest:
1919 TIME_WINDOW = 300 # 5 minutes
2020 SECRET_KEY = environ ["SECRET_KEY" ]
2121
22- def __init__ (
23- self , headers : dict , data : RequestData , request_body : bytes
24- ) -> None :
22+ def __init__ (self , headers : dict , request_body : bytes ) -> None :
2523 self .headers = headers
26- self .data = data
2724 self .request_body = request_body
2825
29- async def validate (self ) -> tuple [str , str ]:
26+ async def validate (self , data : RequestData ) -> tuple [str , str ]:
3027 """validate request"""
3128 self .validate_timestamp ()
3229 self .validate_signature ()
33- container_name = self .get_container_name ()
30+ container_name = self .get_container_name (data )
3431 await self .validate_container_name (container_name )
3532 compose_file = await self .get_compose_file (container_name )
3633 logging .info ("validation passed" )
3734
3835 return container_name , compose_file
3936
37+ async def validate_swarm (self , data : SwarmRequestData ) -> ServiceJsonType :
38+ """validate swarm request"""
39+ self .validate_timestamp ()
40+ self .validate_signature ()
41+ container_name = self .get_container_name (data )
42+ service_json : ServiceJsonType = await self .validate_swarm_service (
43+ container_name
44+ )
45+ logging .info ("validation passed" )
46+
47+ return service_json
48+
4049 def validate_timestamp (self ) -> None :
4150 """raise valueerror on invalid timestamp"""
4251 timestamp = self .headers .get ("x-timestamp" )
@@ -64,9 +73,9 @@ def validate_signature(self):
6473 if not hmac .compare_digest (computed_signature , signature ):
6574 raise ValueError ("invalid signature" )
6675
67- def get_container_name (self ) -> str :
76+ def get_container_name (self , data : RequestData | SwarmRequestData ) -> str :
6877 """extract container name from data"""
69- container_name = self . data .container_name
78+ container_name = data .container_name
7079 if not container_name :
7180 raise ValueError ("no container name defined" )
7281
@@ -87,6 +96,25 @@ async def validate_container_name(self, container_name: str):
8796
8897 raise ValueError ("container_name not found" )
8998
99+ async def validate_swarm_service (
100+ self , container_name : str
101+ ) -> ServiceJsonType :
102+ """validate swarm service name"""
103+ services = await run_command ("docker service ls --format=json" )
104+ for service in services .split ("\n " ):
105+ if not service :
106+ continue
107+
108+ try :
109+ service_json = ServiceJsonType .model_validate_json (service )
110+ except ValueError :
111+ continue
112+
113+ if service_json .Name == container_name :
114+ return service_json
115+
116+ raise ValueError ("container_name not found" )
117+
90118 async def get_compose_file (self , container_name : str ) -> str :
91119 """get absolute compose file path from container config"""
92120 try :
0 commit comments