diff --git a/packages/core/ai_core_sdk/credentials.py b/packages/core/ai_core_sdk/credentials.py
index ca3874d..6499a4b 100644
--- a/packages/core/ai_core_sdk/credentials.py
+++ b/packages/core/ai_core_sdk/credentials.py
@@ -9,7 +9,7 @@
from ai_core_sdk.helpers import get_home
from ai_core_sdk.helpers.constants import (AI_CORE_PREFIX, AUTH_ENDPOINT_SUFFIX, CONFIG_FILE_ENV_VAR, PROFILE_ENV_VAR,
- VCAP_AICORE_SERVICE_NAME, VCAP_SERVICES_ENV_VAR)
+ SERVICE_KEY_ENV_VAR, VCAP_AICORE_SERVICE_NAME, VCAP_SERVICES_ENV_VAR)
from ai_core_sdk.helpers.logging import get_logger
logger = get_logger()
@@ -241,6 +241,37 @@ def _str_or_none(value) -> Optional[str]:
return str(value) if value else None
+def _parse_service_key(credential_values: List[CredentialsValue]) -> Optional[Callable[[CredentialsValue], Optional[str]]]:
+ """Return a source getter for AICORE_SERVICE_KEY if the env var is set and valid JSON, else None.
+
+ AICORE_SERVICE_KEY is expected to be the raw JSON string of a BTP service key, i.e. the
+ ``credentials`` object from a VCAP_SERVICES binding without the outer envelope. Credential
+ fields are extracted using the ``vcap_key`` paths already defined on each ``CredentialsValue``,
+ but with the leading ``'credentials'`` segment stripped (same as the CLI's load_service_key).
+ """
+ raw = os.environ.get(SERVICE_KEY_ENV_VAR)
+ if not raw:
+ return None
+ try:
+ service_key = json.loads(raw)
+ except json.JSONDecodeError as exc:
+ raise ValueError(
+ f"{SERVICE_KEY_ENV_VAR} is set but contains invalid JSON: {exc}"
+ ) from exc
+
+ def _get(cv: CredentialsValue) -> Optional[str]:
+ if not cv.vcap_key:
+ return None
+ # vcap_key is e.g. ('credentials', 'clientid') — drop the 'credentials' prefix
+ key_path = cv.vcap_key[1:]
+ try:
+ return _str_or_none(get_nested_value(service_key, key_path))
+ except KeyError:
+ return None
+
+ return _get
+
+
def fetch_credentials(profile: str = None, credential_values: List[CredentialsValue] = CORE_CREDENTIAL_VALUES,
validate: bool = True, **kwargs) -> Dict[str, str]:
"""
@@ -261,11 +292,17 @@ def fetch_credentials(profile: str = None, credential_values: List[CredentialsVa
except KeyError:
vcap_service = None
+ service_key_getter = _parse_service_key(credential_values)
+
sources = [
Source("kwargs",
lambda cv: _str_or_none(kwargs.get(cv.name))),
Source("environment variables",
lambda cv: _str_or_none(os.environ.get(f'{AI_CORE_PREFIX}_{cv.name.upper()}'))),
+ *(
+ [Source(SERVICE_KEY_ENV_VAR, service_key_getter)]
+ if service_key_getter is not None else []
+ ),
Source("config file",
lambda cv: _str_or_none(config.get(f'{AI_CORE_PREFIX}_{cv.name.upper()}'))),
Source("VCAP service",
diff --git a/packages/core/ai_core_sdk/helpers/constants.py b/packages/core/ai_core_sdk/helpers/constants.py
index 7091330..ba2c5b2 100644
--- a/packages/core/ai_core_sdk/helpers/constants.py
+++ b/packages/core/ai_core_sdk/helpers/constants.py
@@ -8,6 +8,7 @@
DEFAULT_HOME_PATH = os.path.join(os.path.expanduser('~'), '.aicore')
HOME_PATH_ENV_VAR = f'{AI_CORE_PREFIX}_HOME'
PROFILE_ENV_VAR = f'{AI_CORE_PREFIX}_PROFILE'
+SERVICE_KEY_ENV_VAR = f'{AI_CORE_PREFIX}_SERVICE_KEY'
VCAP_AICORE_SERVICE_NAME = 'aicore'
VCAP_SERVICES_ENV_VAR = 'VCAP_SERVICES'
diff --git a/packages/core/docs/ai_core_sdk.credentials.html b/packages/core/docs/ai_core_sdk.credentials.html
index 3621959..6e4a75d 100644
--- a/packages/core/docs/ai_core_sdk.credentials.html
+++ b/packages/core/docs/ai_core_sdk.credentials.html
@@ -254,6 +254,7 @@
NoDefault = NoDefault
Optional = typing.Optional
PROFILE_ENV_VAR = 'AICORE_PROFILE'
+SERVICE_KEY_ENV_VAR = 'AICORE_SERVICE_KEY'
Tuple = typing.Tuple
VCAP_AICORE_SERVICE_NAME = 'aicore'
VCAP_SERVICES_ENV_VAR = 'VCAP_SERVICES'
diff --git a/packages/core/docs/ai_core_sdk.helpers.constants.html b/packages/core/docs/ai_core_sdk.helpers.constants.html
index ed3acc2..3c4437e 100644
--- a/packages/core/docs/ai_core_sdk.helpers.constants.html
+++ b/packages/core/docs/ai_core_sdk.helpers.constants.html
@@ -96,6 +96,7 @@
DEFAULT_HOME_PATH = '/home/runner/.aicore'
HOME_PATH_ENV_VAR = 'AICORE_HOME'
PROFILE_ENV_VAR = 'AICORE_PROFILE'
+SERVICE_KEY_ENV_VAR = 'AICORE_SERVICE_KEY'
VCAP_AICORE_SERVICE_NAME = 'aicore'
VCAP_SERVICES_ENV_VAR = 'VCAP_SERVICES'