55
66Mount path convention::
77
8+ /etc/secrets/appfnd/hana-agent-memory/default/url
9+ /etc/secrets/appfnd/hana-agent-memory/default/uaa
810
11+ ``url`` is the Agent Memory service base URL (plain string).
12+ ``uaa`` is a JSON string with OAuth2 credentials containing at minimum:
13+ ``clientid``, ``clientsecret``, and ``url`` (UAA base URL).
914
10- /etc/secrets/appfnd/hana-agent-memory/default/{field_key}
15+ Env fallback convention::
1116
12- Keys: ``application_url``, ``uaa.url``, ``uaa.clientid``, ``uaa.clientsecret``
13-
14- Env fallback convention (uppercased)::
15-
16- CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_APPLICATION_URL
17- CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_UAA_URL
18- CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_UAA_CLIENTID
19- CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_UAA_CLIENTSECRET
17+ CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_URL
18+ CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_UAA
2019"""
2120
22- from dataclasses import dataclass , field
21+ import json
22+ from dataclasses import dataclass
2323from typing import Optional
2424
2525from sap_cloud_sdk .agent_memory .exceptions import AgentMemoryConfigError
@@ -60,11 +60,18 @@ class AgentMemoryConfig:
6060 def __post_init__ (self ) -> None :
6161 if not self .base_url :
6262 raise AgentMemoryConfigError ("base_url must be a non-empty string" )
63-
64-
65- # NOTE: BindingData must NOT use `from __future__ import annotations`
66- # because the secret resolver checks `f.type is str` at runtime, which requires
67- # actual type objects rather than string annotations.
63+ if self .token_url is not None and not self .token_url :
64+ raise AgentMemoryConfigError (
65+ "token_url must be a non-empty string when provided"
66+ )
67+ if self .client_id is not None and not self .client_id :
68+ raise AgentMemoryConfigError (
69+ "client_id must be a non-empty string when provided"
70+ )
71+ if self .client_secret is not None and not self .client_secret :
72+ raise AgentMemoryConfigError (
73+ "client_secret must be a non-empty string when provided"
74+ )
6875
6976
7077@dataclass
@@ -74,73 +81,42 @@ class BindingData:
7481 All fields must be plain ``str`` to satisfy the resolver contract.
7582 """
7683
77- application_url : str = ""
78- uaa_url : str = field (default = "" , metadata = {"secret" : "uaa.url" })
79- uaa_clientid : str = field (default = "" , metadata = {"secret" : "uaa.clientid" })
80- uaa_clientsecret : str = field (default = "" , metadata = {"secret" : "uaa.clientsecret" })
84+ url : str = ""
85+ uaa : str = ""
8186
8287 def validate (self ) -> None :
8388 """Raise ``AgentMemoryConfigError`` if any required field is empty."""
84- missing = [
85- f
86- for f in ("application_url" , "uaa_url" , "uaa_clientid" , "uaa_clientsecret" )
87- if not getattr (self , f )
88- ]
89- if missing :
89+ if not self .url :
90+ raise AgentMemoryConfigError (
91+ "Agent Memory binding is missing required field: url"
92+ )
93+ if not self .uaa :
9094 raise AgentMemoryConfigError (
91- f "Agent Memory binding is missing required fields: { ', ' . join ( missing ) } "
95+ "Agent Memory binding is missing required field: uaa "
9296 )
9397
9498 def extract_config (self ) -> AgentMemoryConfig :
95- """Derive an ``AgentMemoryConfig`` from the raw binding fields."""
96- return AgentMemoryConfig (
97- base_url = self .application_url ,
98- token_url = self .uaa_url .rstrip ("/" ) + "/oauth/token" ,
99- client_id = self .uaa_clientid ,
100- client_secret = self .uaa_clientsecret ,
101- )
102-
103-
104- _ENV_PREFIX = "CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT"
105-
106- # Explicit env var names — dots are not valid in shell variable names,
107- # so we define these directly rather than deriving them from BindingData metadata keys
108- # (which use dots to match the BTP mount-path file naming convention).
109- _ENV_VARS = {
110- "application_url" : f"{ _ENV_PREFIX } _APPLICATION_URL" ,
111- "uaa_url" : f"{ _ENV_PREFIX } _UAA_URL" ,
112- "uaa_clientid" : f"{ _ENV_PREFIX } _UAA_CLIENTID" ,
113- "uaa_clientsecret" : f"{ _ENV_PREFIX } _UAA_CLIENTSECRET" ,
114- }
115-
116-
117- def _load_binding_from_env () -> BindingData :
118- """Read Agent Memory binding from environment variables.
119-
120- Raises:
121- AgentMemoryConfigError: If any required variable is absent.
122- """
123- import os
124-
125- binding = BindingData ()
126- missing : list [str ] = []
127- for attr , var in _ENV_VARS .items ():
128- value = os .environ .get (var )
129- if not value :
130- missing .append (var )
131- else :
132- setattr (binding , attr , value )
133- if missing :
134- raise AgentMemoryConfigError (
135- f"Missing required environment variables: { ', ' .join (missing )} "
136- )
137- return binding
99+ """Parse the UAA JSON string and return an ``AgentMemoryConfig``."""
100+ try :
101+ uaa_data = json .loads (self .uaa , strict = False )
102+ except json .JSONDecodeError as e :
103+ raise AgentMemoryConfigError (f"Failed to parse uaa JSON: { e } " )
104+
105+ try :
106+ return AgentMemoryConfig (
107+ base_url = self .url ,
108+ token_url = uaa_data ["url" ].rstrip ("/" ) + "/oauth/token" ,
109+ client_id = uaa_data ["clientid" ],
110+ client_secret = uaa_data ["clientsecret" ],
111+ )
112+ except KeyError as e :
113+ raise AgentMemoryConfigError (f"Missing required field in uaa JSON: { e } " )
138114
139115
140116def _load_config_from_env () -> AgentMemoryConfig :
141117 """Load Agent Memory configuration from a mounted volume or environment variables.
142118
143- Tries (in order) :
119+ Uses the secret resolver with fallback order:
144120 1. Mount at ``/etc/secrets/appfnd/hana-agent-memory/default/``
145121 2. Environment variables ``CLOUD_SDK_CFG_HANA_AGENT_MEMORY_DEFAULT_*``
146122
@@ -150,24 +126,24 @@ def _load_config_from_env() -> AgentMemoryConfig:
150126 Raises:
151127 AgentMemoryConfigError: If configuration cannot be loaded or is incomplete.
152128 """
153- from sap_cloud_sdk .core .secret_resolver .resolver import _load_from_mount
129+ from sap_cloud_sdk .core .secret_resolver import (
130+ read_from_mount_and_fallback_to_env_var ,
131+ )
154132
155- mount_error : Exception | None = None
156133 try :
157134 binding = BindingData ()
158- _load_from_mount ("/etc/secrets/appfnd" , "hana-agent-memory" , "default" , binding )
159- binding .validate ()
160- return binding .extract_config ()
161- except Exception as exc :
162- mount_error = exc
163-
164- try :
165- binding = _load_binding_from_env ()
135+ read_from_mount_and_fallback_to_env_var (
136+ base_volume_mount = "/etc/secrets/appfnd" ,
137+ base_var_name = "CLOUD_SDK_CFG" ,
138+ module = "hana-agent-memory" ,
139+ instance = "default" ,
140+ target = binding ,
141+ )
166142 binding .validate ()
167143 return binding .extract_config ()
168144 except AgentMemoryConfigError :
169145 raise
170146 except Exception as exc :
171147 raise AgentMemoryConfigError (
172- f"Failed to load Agent Memory configuration: mount= { mount_error } ; env= { exc } "
148+ f"Failed to load Agent Memory configuration: { exc } "
173149 ) from exc
0 commit comments