Skip to content

Commit 370ebd3

Browse files
committed
modified as per review
1 parent be6662e commit 370ebd3

4 files changed

Lines changed: 28 additions & 14 deletions

File tree

python-sdk/exospherehost/node/BaseNode.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ class Secrets(BaseModel):
5050

5151
async def _execute(self, inputs: Inputs, secrets: Secrets) -> Outputs | List[Outputs]:
5252
"""
53-
Internal method to execute the node with validated inputs.
53+
Internal method to execute the node with validated inputs and secrets.
5454
5555
Args:
5656
inputs (Inputs): The validated input data for this execution.
57+
secrets (Secrets): The validated secrets data for this execution.
5758
5859
Returns:
5960
Outputs | List[Outputs]: The output(s) produced by the node.

python-sdk/exospherehost/runtime.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ async def _get_secrets(self, state_id: str) -> Dict[str, str]:
245245

246246
if response.status != 200:
247247
logger.error(f"Failed to get secrets for state {state_id}: {res}")
248+
return {}
248249

249250
return res
250251

@@ -280,7 +281,7 @@ def _validate_nodes(self):
280281
errors.append(f"{node.__name__} does not have an Secrets class that inherits from pydantic.BaseModel")
281282

282283
for field_name, field_info in node.Secrets.model_fields.items():
283-
if field_info.annotation != str:
284+
if field_info.annotation is not str:
284285
errors.append(f"{node.__name__}.Secrets field '{field_name}' must be of type str, got {field_info.annotation}")
285286

286287
# Find nodes with the same __class__.__name__

state-manager/app/models/db/graph_template_model.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from ..node_template_model import NodeTemplate
99
from pymongo import IndexModel
1010
from typing import Dict
11-
from app.utils.encrypter import encrypter
11+
from app.utils.encrypter import get_encrypter
1212

1313
class GraphTemplate(BaseDatabaseModel):
1414
name: str = Field(..., description="Name of the graph")
@@ -53,11 +53,6 @@ def _validate_secret_value(cls, secret_value: str) -> None:
5353
if not re.match(url_safe_base64_pattern, secret_value):
5454
raise ValueError("Value must be URL-safe base64 encoded")
5555

56-
# Check if the string length is valid for base64 encoding
57-
# Base64 encoding increases size by ~33%, and we need at least 12 bytes nonce
58-
if len(secret_value) % 4 != 0:
59-
raise ValueError("Value length is not valid for base64 encoding")
60-
6156
# Try to decode as base64 to ensure it's valid
6257
try:
6358
decoded = base64.urlsafe_b64decode(secret_value)
@@ -68,15 +63,17 @@ def _validate_secret_value(cls, secret_value: str) -> None:
6863

6964

7065
def set_secrets(self, secrets: Dict[str, str]) -> "GraphTemplate":
71-
self.secrets = {secret_name: encrypter.encrypt(secret_value) for secret_name, secret_value in secrets.items()}
66+
self.secrets = {secret_name: get_encrypter().encrypt(secret_value) for secret_name, secret_value in secrets.items()}
7267
return self
7368

7469
def get_secrets(self) -> Dict[str, str]:
7570
if not self.secrets:
7671
return {}
77-
return {secret_name: encrypter.decrypt(secret_value) for secret_name, secret_value in self.secrets.items()}
72+
return {secret_name: get_encrypter().decrypt(secret_value) for secret_name, secret_value in self.secrets.items()}
7873

79-
def get_secret(self, secret_name: str) -> str:
74+
def get_secret(self, secret_name: str) -> str | None:
8075
if not self.secrets:
81-
return ""
82-
return encrypter.decrypt(self.secrets[secret_name])
76+
return None
77+
if secret_name not in self.secrets:
78+
return None
79+
return get_encrypter().decrypt(self.secrets[secret_name])

state-manager/app/utils/encrypter.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,19 @@ def decrypt(self, encrypted_secret: str) -> str:
3131
ciphertext = encrypted_secret_bytes[12:]
3232
return self._aesgcm.decrypt(nonce, ciphertext, None).decode()
3333

34-
encrypter = Encrypter()
34+
_encrypter_instance = None
35+
36+
def get_encrypter() -> Encrypter:
37+
"""
38+
Get the Encrypter instance, creating it on first call.
39+
40+
Returns:
41+
Encrypter: The singleton Encrypter instance.
42+
43+
Raises:
44+
ValueError: If SECRETS_ENCRYPTION_KEY is not set or invalid.
45+
"""
46+
global _encrypter_instance
47+
if _encrypter_instance is None:
48+
_encrypter_instance = Encrypter()
49+
return _encrypter_instance

0 commit comments

Comments
 (0)