Skip to content

Commit edcd6c4

Browse files
authored
Merge pull request #34 from splitio/3.5.8-addprojectandorglevel
Features: Added optional org_identifier and project_identifier support for Harness microclients These parameters can be set at client initialization or passed to individual method calls Parameters are only included in API request URLs when they are set (not None) When not provided, they are completely omitted from URLs rather than being passed as empty strings Applies to all Harness microclients: harness_project, harness_user, harness_group, harness_apikey, service_account, token, role, resource_group, and role_assignment Added filterType support to the group endpoint in order to allow fitlering by resourcegroups Update the client instantiation to warn when using the legacy bearer auth along with the x-api-key auth
2 parents c46ee45 + b5c9c9b commit edcd6c4

27 files changed

+3720
-470
lines changed

CHANGES.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@ CHANGELOG
33

44
This file tracks the version history and changes made to the Split/Harness FME Python API Client library.
55

6+
3.5.8 (December 10, 2025)
7+
-------------------------
8+
Features:
9+
- Added optional org_identifier and project_identifier support for Harness microclients
10+
- These parameters can be set at client initialization or passed to individual method calls
11+
- Parameters are only included in API request URLs when they are set (not None)
12+
- When not provided, they are completely omitted from URLs rather than being passed as empty strings
13+
- Applies to all Harness microclients: harness_project, harness_user, harness_group,
14+
harness_apikey, service_account, token, role, resource_group, and role_assignment
15+
16+
- Added filterType support to the group endpoint in order to allow fitlering by resourcegroups
17+
- Update the client instantiation to warn when using the legacy bearer auth along with the x-api-key auth
18+
19+
620
3.5.7 (November 26, 2025)
721
-------------------------
822
Bug Fixes:

README.md

Lines changed: 80 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@ Full documentation on this Python wrapper is available in [this link](https://he
88

99
## Using in Harness Mode
1010

11-
Starting with version 3.5.0, the Split API client supports operating in "harness mode" to interact with both Split and Harness APIs. This is required for usage in environments that have been migrated to Harness and want to use the new features. Existing API keys will continue to work with the non-deprecated endpoints after migration, but new Harness Tokens will be required for Harness mode.
11+
Starting with version 3.5.0, the Split API client supports operating in "harness mode" to interact with both Split and Harness APIs. This is required for usage in environments that have been migrated to Harness **and** want to use the new features. Operating not in harness mode will work as it did before with existing Split bearer tokens, but the deprecated endpoints mentioned below will not function.
1212

1313
For detailed information about Harness API endpoints, please refer to the [official Harness API documentation](https://apidocs.harness.io/).
1414

1515
### Authentication in Harness Mode
1616

17-
The client supports multiple authentication scenarios:
17+
**Important:** Harness mode requires a `harness_token` (Harness API key). Split API keys (`apikey`) are **not supported** in harness mode.
1818

19-
1. Harness-specific endpoints always use the 'x-api-key' header format
20-
2. Split endpoints will use the 'x-api-key' header when using the harness_token
21-
3. Split endpoints will use the normal 'Authorization' header when using the apikey
22-
4. If both harness_token and apikey are provided, the client will use the harness_token for Harness endpoints and the apikey for Split endpoints
19+
If your account has been migrated to Harness, you should create a new Harness API key to use with this client. The `harness_token` is used for both Split API endpoints and Harness-specific endpoints via the `x-api-key` header.
20+
21+
For non-migrated accounts that need to use Split API keys with Bearer authentication, use the standard (non-harness) mode instead.
2322

2423
### Base URLs and Endpoints
2524

@@ -44,19 +43,20 @@ To use the client in harness mode:
4443
```python
4544
from splitapiclient.main import get_client
4645

47-
# Option 1: Use harness_token for Harness endpoints and apikey for Split endpoints
46+
# Basic harness mode setup with required harness_token
4847
client = get_client({
4948
'harness_mode': True,
50-
'harness_token': 'YOUR_HARNESS_TOKEN', # Used for Harness-specific endpoints
51-
'apikey': 'YOUR_SPLIT_API_KEY', # Used for existing Split endpoints
49+
'harness_token': 'YOUR_HARNESS_TOKEN', # Required: Harness API key
5250
'account_identifier': 'YOUR_HARNESS_ACCOUNT_ID' # Required for Harness operations
5351
})
5452

55-
# Option 2: Use harness_token for all operations (if apikey is not provided)
53+
# Include optional org_identifier and project_identifier
5654
client = get_client({
5755
'harness_mode': True,
58-
'harness_token': 'YOUR_HARNESS_TOKEN', # Used for both Harness and Split endpoints
59-
'account_identifier': 'YOUR_HARNESS_ACCOUNT_ID'
56+
'harness_token': 'YOUR_HARNESS_TOKEN',
57+
'account_identifier': 'YOUR_HARNESS_ACCOUNT_ID',
58+
'org_identifier': 'YOUR_ORG_ID', # Optional: organization identifier
59+
'project_identifier': 'YOUR_PROJECT_ID' # Optional: project identifier
6060
})
6161
```
6262

@@ -97,15 +97,30 @@ Basic example:
9797
# Account identifier is required for all Harness operations
9898
account_id = 'YOUR_ACCOUNT_IDENTIFIER'
9999

100-
# List all tokens
100+
# List all tokens (org_identifier and project_identifier are optional)
101101
tokens = client.token.list(account_id)
102102
for token in tokens:
103103
print(f"Token: {token.name}, ID: {token.id}")
104104

105-
# List service accounts
106-
service_accounts = client.service_account.list(account_id)
105+
# List service accounts with org and project identifiers
106+
org_id = 'YOUR_ORG_IDENTIFIER'
107+
project_id = 'YOUR_PROJECT_IDENTIFIER'
108+
service_accounts = client.service_account.list(account_id, org_identifier=org_id, project_identifier=project_id)
107109
for sa in service_accounts:
108110
print(f"Service Account: {sa.name}, ID: {sa.id}")
111+
112+
# If org_identifier and project_identifier are set at client initialization, you can omit them
113+
client = get_client({
114+
'harness_mode': True,
115+
'harness_token': 'YOUR_HARNESS_TOKEN',
116+
'account_identifier': account_id,
117+
'org_identifier': org_id,
118+
'project_identifier': project_id
119+
})
120+
121+
# Now you can call methods without specifying identifiers
122+
service_accounts = client.service_account.list() # Uses default identifiers
123+
projects = client.harness_project.list() # Uses default identifiers
109124
```
110125

111126
For most creation, update, and delete endpoints for harness specific resources, you will need to pass through the JSON body directly.
@@ -130,24 +145,68 @@ new_sa = client.service_account.create(sa_data, account_id)
130145
client.harness_user.add_user_to_groups(user.id, [group.id], account_id)
131146
```
132147

148+
### Harness Groups
149+
150+
The `harness_group.list()` method supports an optional `filterType` parameter to filter groups:
151+
152+
```python
153+
# List all groups (default behavior)
154+
all_groups = client.harness_group.list()
155+
156+
# List groups with filterType to exclude inherited groups
157+
groups = client.harness_group.list(filterType='EXCLUDE_INHERITED_GROUPS')
158+
159+
# List groups with filterType and other optional parameters
160+
groups = client.harness_group.list(
161+
account_identifier='YOUR_ACCOUNT_ID',
162+
org_identifier='YOUR_ORG_ID',
163+
project_identifier='YOUR_PROJECT_ID',
164+
filterType='INCLUDE_INHERITED_GROUPS'
165+
)
166+
```
167+
168+
**Note:** The `filterType` parameter is optional. When not provided (or set to `None`), it will be omitted from the API request. Valid values depend on the Harness API specification.
169+
133170

134171
For detailed examples and API specifications for each resource, please refer to the [Harness API documentation](https://apidocs.harness.io/).
135172

136-
### Setting Default Account Identifier
173+
### Setting Default Identifiers
137174

138-
To avoid specifying the account identifier with every request:
175+
To avoid specifying identifiers with every request, you can set default values when creating the client:
139176

140177
```python
141-
# Set default account identifier when creating the client
178+
# Set default identifiers when creating the client
142179
client = get_client({
143180
'harness_mode': True,
144181
'harness_token': 'YOUR_HARNESS_TOKEN',
145-
'account_identifier': 'YOUR_ACCOUNT_IDENTIFIER'
182+
'account_identifier': 'YOUR_ACCOUNT_IDENTIFIER', # Required
183+
'org_identifier': 'YOUR_ORG_IDENTIFIER', # Optional
184+
'project_identifier': 'YOUR_PROJECT_IDENTIFIER' # Optional
146185
})
147186

148-
# Now you can make calls without specifying account_identifier in each request
187+
# Now you can make calls without specifying identifiers in each request
149188
tokens = client.token.list() # account_identifier is automatically included
150-
projects = client.harness_project.list() # account_identifier is automatically included
189+
projects = client.harness_project.list() # account_identifier and org_identifier are automatically included (project_identifier is not used for projects endpoint)
190+
```
191+
192+
**Note on Optional Identifiers:**
193+
- `account_identifier` is **required** for all Harness operations
194+
- `org_identifier` and `project_identifier` are **optional** and will be omitted from API requests if not provided
195+
- If `org_identifier` or `project_identifier` are not set, they will not appear in the URL at all (not even as empty parameters)
196+
- **Important:** The `harness_project` microclient does **not** support `project_identifier` as a query parameter. The projects endpoint only uses `org_identifier` (and `account_identifier`). Other microclients (service_account, token, role, etc.) do support `project_identifier`.
197+
- You can override default identifiers by passing them as parameters to individual method calls:
198+
199+
```python
200+
# Override default identifiers for a specific request
201+
# Note: project_identifier is not used for harness_project endpoints
202+
projects = client.harness_project.list(
203+
account_identifier='DIFFERENT_ACCOUNT_ID',
204+
org_identifier='DIFFERENT_ORG_ID'
205+
)
206+
207+
# Use default identifiers but override only org_identifier
208+
# Note: project_identifier is not used for harness_project endpoints
209+
projects = client.harness_project.list(org_identifier='DIFFERENT_ORG_ID')
151210
```
152211

153212
## Quick Setup

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "splitapiclient"
7-
version = "3.5.7"
7+
version = "3.5.8"
88
license = "Apache-2.0"
99
description = "This Python Library provides full support for Split REST Admin API, allow creating, deleting and editing Environments, Splits, Split Definitions, Segments, Segment Keys, Users, Groups, API Keys, Change Requests, Attributes and Identities"
1010
classifiers = [

splitapiclient/main/harness_apiclient.py

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import absolute_import, division, print_function, \
22
unicode_literals
3+
import warnings
34
from splitapiclient.main.apiclient import BaseApiClient
45
from splitapiclient.http_clients.harness_client import HarnessHttpClient
56
from splitapiclient.util.exceptions import InsufficientConfigArgumentsException
@@ -45,14 +46,18 @@ def __init__(self, config):
4546
Class constructor.
4647
4748
:param config: Dictionary containing options required to instantiate
48-
the API client. Should have AT LEAST one of the following keys:
49-
- 'apikey': Split API key for authentication with Split endpoints
50-
- 'harness_token': Harness authentication token used for x-api-key header with Harness endpoints
51-
If harness_token is not provided, apikey will be used for all operations
49+
the API client. Required keys:
50+
- 'harness_token': Harness authentication token used for x-api-key header
51+
This token is used for both Split API and Harness API endpoints.
52+
Note: Split API keys (apikey) are not supported in harness mode.
53+
Migrated accounts should create new Harness API keys.
54+
Optional keys:
5255
- 'base_url': Base url where the Split API is hosted (optional, defaults to Split URL)
5356
- 'base_url_v3': Base url where the Split API v3 is hosted (optional, defaults to Split URL)
5457
- 'harness_base_url': Base url where the Harness API is hosted (optional, defaults to Harness URL)
5558
- 'account_identifier': Harness account identifier to use for all Harness operations (optional)
59+
- 'org_identifier': Harness organization identifier to use for all Harness operations (optional)
60+
- 'project_identifier': Harness project identifier to use for all Harness operations (optional)
5661
'''
5762
# Set up Split API base URLs for existing endpoints
5863
if 'base_url' in config:
@@ -72,30 +77,28 @@ def __init__(self, config):
7277
else:
7378
self._harness_base_url = self.BASE_HARNESS_URL
7479

75-
# Check if at least one authentication method is provided
76-
if 'apikey' not in config and 'harness_token' not in config:
80+
# Require harness_token in harness mode
81+
if 'harness_token' not in config:
7782
raise InsufficientConfigArgumentsException(
78-
'At least one of the following keys must be present in the config dict for harness mode: apikey, harness_token'
83+
'harness_token is required in harness mode. Split API keys (apikey) are not supported by this client. '
84+
'Please create a Harness API key for your migrated account and use the harness_token for authentication.'
7985
)
8086

81-
# Set up authentication tokens
82-
self._apikey = config.get('apikey')
83-
self._harness_token = config.get('harness_token')
87+
# Use harness_token for all operations
88+
self._harness_token = config['harness_token']
89+
auth_token = self._harness_token
8490

85-
# If harness_token is not provided, use apikey for all operations
86-
# If apikey is not provided, use harness_token for all operations
87-
split_auth_token = self._apikey if self._apikey else self._harness_token
88-
harness_auth_token = self._harness_token if self._harness_token else self._apikey
89-
90-
# Store the account identifier
91+
# Store the account identifier, org identifier, and project identifier
9192
self._account_identifier = config.get('account_identifier')
93+
self._org_identifier = config.get('org_identifier')
94+
self._project_identifier = config.get('project_identifier')
9295

93-
# Create HTTP clients for Split endpoints
94-
split_http_client = HarnessHttpClient(self._base_url, split_auth_token)
95-
split_http_clientv3 = HarnessHttpClient(self._base_url_v3, split_auth_token)
96+
# Create HTTP clients - use same token for both Split and Harness endpoints
97+
split_http_client = HarnessHttpClient(self._base_url, auth_token)
98+
split_http_clientv3 = HarnessHttpClient(self._base_url_v3, auth_token)
9699

97100
# Create HTTP client for Harness endpoints
98-
harness_http_client = HarnessHttpClient(self._harness_base_url, harness_auth_token)
101+
harness_http_client = HarnessHttpClient(self._harness_base_url, auth_token)
99102

100103
# Standard microclients using Split endpoints
101104
self._environment_client = EnvironmentMicroClient(split_http_client)
@@ -114,15 +117,15 @@ def __init__(self, config):
114117
self._flag_set_client = FlagSetMicroClient(split_http_clientv3)
115118

116119
# Harness-specific microclients using Harness endpoints
117-
self._token_client = TokenMicroClient(harness_http_client, self._account_identifier)
118-
self._harness_apikey_client = HarnessApiKeyMicroClient(harness_http_client, self._account_identifier)
119-
self._service_account_client = ServiceAccountMicroClient(harness_http_client, self._account_identifier)
120-
self._harness_user_client = HarnessUserMicroClient(harness_http_client, self._account_identifier)
121-
self._harness_group_client = HarnessGroupMicroClient(harness_http_client, self._account_identifier)
122-
self._role_client = RoleMicroClient(harness_http_client, self._account_identifier)
123-
self._resource_group_client = ResourceGroupMicroClient(harness_http_client, self._account_identifier)
124-
self._role_assignment_client = RoleAssignmentMicroClient(harness_http_client, self._account_identifier)
125-
self._harness_project_client = HarnessProjectMicroClient(harness_http_client, self._account_identifier)
120+
self._token_client = TokenMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
121+
self._harness_apikey_client = HarnessApiKeyMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
122+
self._service_account_client = ServiceAccountMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
123+
self._harness_user_client = HarnessUserMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
124+
self._harness_group_client = HarnessGroupMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
125+
self._role_client = RoleMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
126+
self._resource_group_client = ResourceGroupMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
127+
self._role_assignment_client = RoleAssignmentMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
128+
self._harness_project_client = HarnessProjectMicroClient(harness_http_client, self._account_identifier, self._org_identifier, self._project_identifier)
126129

127130
@property
128131
def traffic_types(self):

0 commit comments

Comments
 (0)