Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/core/PYPIDESCRIPTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ for scenario in scenarios.resources:
There are different options to persist the client credentials
(in this order of precedence):
- in code via keyword arguments (see above),
- from AICORE_SERVICE_KEY environment variable, if exists
- environment variables,
- profile configuration file.
- from VCAP_SERVICES environment variable, if exists
Expand Down
7 changes: 4 additions & 3 deletions packages/core/ai_core_sdk/ai_core_v2_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,10 @@ def from_env(profile_name: str = None,
A specific path to a config, that should be used, can be set via the environment variable AICORE_CONFIG.
The hierarchy of precedence is:
1. keyword argument
2. environment variable
3. configuration file
4. value from VCAP_SERVICES environment variable, if exists
2. value from AICORE_SERVICE_KEY environment variable, if exists
3. environment variable
4. configuration file
5. value from VCAP_SERVICES environment variable, if exists

:param profile_name: name of the profile to use, defaults to None. If None is passed, the profile is read from
the environment variable AICORE_PROFILE. If this is not set, the default profile is used.
Expand Down
6 changes: 3 additions & 3 deletions packages/core/ai_core_sdk/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def fetch_credentials(profile: str = None, credential_values: List[CredentialsVa
"""
Fetch credentials from a single source based on precedence.

Precedence order: kwargs > separate environment variables > service key > config file > VCAP service
Precedence order: kwargs > service key > separate environment variables > config file > VCAP service

Once a source is selected (first one with any credential), all credentials
come from that source only. Resource group is an exception and follows
Expand All @@ -298,11 +298,11 @@ def fetch_credentials(profile: str = None, credential_values: List[CredentialsVa
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()}'))),
# A service key is already the inner credentials object, so the leading `credentials` segment is stripped.
Source("service key",
lambda cv, service_key = _load_service_key(): _str_or_none(_get_nested_value_safe(service_key, cv.vcap_key[1:])) if cv.vcap_key else None),
Source("environment variables",
lambda cv: _str_or_none(os.environ.get(f'{AI_CORE_PREFIX}_{cv.name.upper()}'))),
Source("config file",
lambda cv: _str_or_none(config.get(f'{AI_CORE_PREFIX}_{cv.name.upper()}'))),
Source("VCAP service",
Expand Down
14 changes: 7 additions & 7 deletions packages/core/tests/ai_core_client/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ def test_fetch_credentials_from_service_key_x509(self, mock_logger):
mock_logger.debug.assert_any_call("Using credentials from: service key")

@patch('ai_core_sdk.credentials.logger')
def test_service_key_lower_precedence_than_env_vars(self, mock_logger):
def test_service_key_higher_precedence_than_env_vars(self, mock_logger):
mock_logger.debug = MagicMock()

service_key = {
Expand All @@ -349,12 +349,12 @@ def test_service_key_lower_precedence_than_env_vars(self, mock_logger):
}):
credentials = fetch_credentials()

# env vars win
self.assertEqual(credentials['client_id'], 'env-client-id')
self.assertEqual(credentials['client_secret'], 'env-client-secret')
self.assertEqual(credentials['auth_url'], 'https://env-auth-url/oauth/token')
self.assertEqual(credentials['base_url'], 'https://env-base-url/v2')
mock_logger.debug.assert_any_call("Using credentials from: environment variables")
# service key wins over individual env vars
self.assertEqual(credentials['client_id'], 'sk-client-id')
self.assertEqual(credentials['client_secret'], 'sk-client-secret')
self.assertEqual(credentials['auth_url'], 'https://sk-auth-url/oauth/token')
self.assertEqual(credentials['base_url'], 'https://sk-api-url/v2')
mock_logger.debug.assert_any_call("Using credentials from: service key")

def test_service_key_invalid_json_raises(self):
with patch.dict(os.environ, {ENV_VAR_AICORE_SERVICE_KEY: 'not-valid-json'}):
Expand Down
26 changes: 26 additions & 0 deletions packages/gen/README_sphynx.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ In the table below, you can see which models and vendor specific langchain packa

There are different ways to configure the SAP AI Core access (listed in order of precedence):

- from AICORE_SERVICE_KEY environment variable, if it exists
- environment variables
- (profile) configuration file
- from VCAP_SERVICES environment variable, if it exists
Expand Down Expand Up @@ -72,6 +73,22 @@ as an alternative to client secret.
- `AICORE_CERT_STR`: This is the content of the X.509 certificate as a string
- `AICORE_KEY_STR`: This is the content of the X.509 key as a string

### AICORE_SERVICE_KEY environment variable

If you have an SAP AI Core service key (downloaded from BTP), you can pass it as a single environment variable instead of setting each credential separately. The SDK extracts `clientid`, `clientsecret`, `url`, and `AI_API_URL` from it automatically. You still need to set `AICORE_RESOURCE_GROUP` separately, as the resource group is not part of the service key.

```bash
export AICORE_SERVICE_KEY='{
"serviceurls": {
"AI_API_URL": "https://api.ai.* * *.cfapps.sap.hana.ondemand.com"
},
"clientid": "* * * ",
"clientsecret": "* * * ",
"url": "https://* * * .authentication.sap.hana.ondemand.com"
}'
export AICORE_RESOURCE_GROUP="default"
```

### Configuration files

By default, the configuration file is located at `~/.aicore/config.json`. You can change the directory where the config file is located by setting the `AICORE_HOME` environment variable.
Expand Down Expand Up @@ -104,6 +121,15 @@ The configuration file should be:

or

```json
{
"AICORE_SERVICE_KEY": "{\"serviceurls\":{\"AI_API_URL\":\"https://api.ai.***.cfapps.sap.hana.ondemand.com\"},\"clientid\":\"***\",\"clientsecret\":\"***\",\"url\":\"https://***.authentication.sap.hana.ondemand.com\"}",
"AICORE_RESOURCE_GROUP": "***"
}
```

or

```json
{
"AICORE_AUTH_URL": "https://* * * .authentication.cert.sap.hana.ondemand.com",
Expand Down
25 changes: 25 additions & 0 deletions packages/gen/docs/gen_ai_hub/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ The values can be set as environment variables are through config files. For mos
The config files should be placed in AI Core home folder. Which can be set using the env var `AICORE_HOME`, it is set to
`~/.aicore`, by default.

### AICORE_SERVICE_KEY environment variable

If you have an SAP AI Core service key (downloaded from BTP), you can pass it as a single environment variable instead of setting each credential separately. The SDK extracts `clientid`, `clientsecret`, `url`, and `AI_API_URL` from it automatically. You still need to set `AICORE_RESOURCE_GROUP` separately, as the resource group is not part of the service key.

```bash
export AICORE_SERVICE_KEY='{
"serviceurls": {
"AI_API_URL": "https://api.ai.* * *.cfapps.sap.hana.ondemand.com"
},
"clientid": "* * * ",
"clientsecret": "* * * ",
"url": "https://* * * .authentication.sap.hana.ondemand.com"
}',
export AICORE_RESOURCE_GROUP="default"
```

To fetch the values from config file instead of setting environment variables, create a config under path `<AICORE_HOME>/config.json`
```json
{
Expand All @@ -36,6 +52,15 @@ To fetch the values from config file instead of setting environment variables, c

or

```json
{
"AICORE_SERVICE_KEY": "{\"serviceurls\":{\"AI_API_URL\":\"https://api.ai.***.cfapps.sap.hana.ondemand.com\"},\"clientid\":\"***\",\"clientsecret\":\"***\",\"url\":\"https://***.authentication.sap.hana.ondemand.com\"}",
"AICORE_RESOURCE_GROUP": "***"
}
```

or

```json
{
"AICORE_AUTH_URL": "https://* * * .authentication.cert.sap.hana.ondemand.com",
Expand Down