ibm-watsonx-orchestrate 1.6.0b0__py3-none-any.whl → 1.6.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ibm_watsonx_orchestrate/__init__.py +1 -1
- ibm_watsonx_orchestrate/agent_builder/agents/agent.py +1 -0
- ibm_watsonx_orchestrate/agent_builder/agents/types.py +5 -1
- ibm_watsonx_orchestrate/agent_builder/agents/webchat_customizations/__init__.py +2 -0
- ibm_watsonx_orchestrate/agent_builder/agents/webchat_customizations/prompts.py +34 -0
- ibm_watsonx_orchestrate/agent_builder/agents/webchat_customizations/welcome_content.py +20 -0
- ibm_watsonx_orchestrate/agent_builder/connections/__init__.py +2 -2
- ibm_watsonx_orchestrate/agent_builder/connections/connections.py +21 -7
- ibm_watsonx_orchestrate/agent_builder/connections/types.py +39 -36
- ibm_watsonx_orchestrate/agent_builder/tools/flow_tool.py +83 -0
- ibm_watsonx_orchestrate/agent_builder/tools/types.py +7 -1
- ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +56 -18
- ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +104 -21
- ibm_watsonx_orchestrate/cli/commands/chat/chat_command.py +2 -0
- ibm_watsonx_orchestrate/cli/commands/connections/connections_command.py +26 -18
- ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +61 -61
- ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +1 -1
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +118 -30
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +22 -9
- ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +2 -2
- ibm_watsonx_orchestrate/cli/commands/server/server_command.py +123 -5
- ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py +9 -3
- ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +107 -22
- ibm_watsonx_orchestrate/client/agents/agent_client.py +74 -6
- ibm_watsonx_orchestrate/client/base_api_client.py +2 -1
- ibm_watsonx_orchestrate/client/connections/connections_client.py +18 -9
- ibm_watsonx_orchestrate/client/connections/utils.py +4 -2
- ibm_watsonx_orchestrate/client/local_service_instance.py +1 -1
- ibm_watsonx_orchestrate/client/service_instance.py +3 -3
- ibm_watsonx_orchestrate/client/tools/tempus_client.py +8 -3
- ibm_watsonx_orchestrate/client/utils.py +10 -0
- ibm_watsonx_orchestrate/docker/compose-lite.yml +228 -67
- ibm_watsonx_orchestrate/docker/default.env +32 -13
- ibm_watsonx_orchestrate/docker/proxy-config-single.yaml +12 -0
- ibm_watsonx_orchestrate/flow_builder/flows/flow.py +15 -5
- ibm_watsonx_orchestrate/flow_builder/utils.py +78 -48
- ibm_watsonx_orchestrate/run/connections.py +4 -4
- {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.2.dist-info}/METADATA +5 -3
- {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.2.dist-info}/RECORD +42 -37
- {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.2.dist-info}/WHEEL +0 -0
- {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.2.dist-info}/entry_points.txt +0 -0
- {ibm_watsonx_orchestrate-1.6.0b0.dist-info → ibm_watsonx_orchestrate-1.6.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,10 @@
|
|
1
1
|
import logging
|
2
2
|
import rich
|
3
3
|
import jwt
|
4
|
+
import sys
|
4
5
|
|
5
6
|
from ibm_watsonx_orchestrate.cli.config import Config, ENV_WXO_URL_OPT, ENVIRONMENTS_SECTION_HEADER, CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT, CHAT_UI_PORT
|
6
|
-
from ibm_watsonx_orchestrate.client.utils import is_local_dev, AUTH_CONFIG_FILE_FOLDER, AUTH_SECTION_HEADER, AUTH_MCSP_TOKEN_OPT, AUTH_CONFIG_FILE
|
7
|
+
from ibm_watsonx_orchestrate.client.utils import is_local_dev, is_ibm_cloud, AUTH_CONFIG_FILE_FOLDER, AUTH_SECTION_HEADER, AUTH_MCSP_TOKEN_OPT, AUTH_CONFIG_FILE
|
7
8
|
|
8
9
|
from ibm_watsonx_orchestrate.client.agents.agent_client import AgentClient
|
9
10
|
|
@@ -19,7 +20,41 @@ class ChannelsWebchatController:
|
|
19
20
|
def get_native_client(self):
|
20
21
|
self.native_client = instantiate_client(AgentClient)
|
21
22
|
return self.native_client
|
22
|
-
|
23
|
+
|
24
|
+
def extract_tenant_id_from_crn(self, crn: str) -> str:
|
25
|
+
is_ibm_cloud_env = is_ibm_cloud()
|
26
|
+
if is_ibm_cloud_env:
|
27
|
+
try:
|
28
|
+
parts = crn.split("a/")[1].split(":")
|
29
|
+
account_part = parts[0]
|
30
|
+
instance_part = parts[1]
|
31
|
+
tenant_id = f"{account_part}_{instance_part}"
|
32
|
+
return tenant_id
|
33
|
+
except (IndexError, AttributeError):
|
34
|
+
raise ValueError(f"Invalid CRN format: {crn}")
|
35
|
+
else:
|
36
|
+
try:
|
37
|
+
parts = crn.split("sub/")[1].split(":")
|
38
|
+
account_part = parts[0]
|
39
|
+
instance_part = parts[1]
|
40
|
+
tenant_id = f"{account_part}_{instance_part}"
|
41
|
+
return tenant_id
|
42
|
+
except (IndexError, AttributeError):
|
43
|
+
raise ValueError(f"Invalid CRN format: {crn}")
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
def check_crn_is_correct(self, crn: str):
|
48
|
+
parts = crn.split("a/")[1].split(":")
|
49
|
+
instance_part_crn = parts[1]
|
50
|
+
cfg = Config()
|
51
|
+
active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
|
52
|
+
url = cfg.get(ENVIRONMENTS_SECTION_HEADER, active_env, ENV_WXO_URL_OPT)
|
53
|
+
instance_part_url = url.rstrip("/").split("/")[-1]
|
54
|
+
if instance_part_crn == instance_part_url:
|
55
|
+
return True
|
56
|
+
else:
|
57
|
+
return False
|
23
58
|
|
24
59
|
def get_agent_id(self, agent_name: str):
|
25
60
|
native_client = self.get_native_client()
|
@@ -39,7 +74,7 @@ class ChannelsWebchatController:
|
|
39
74
|
raise ValueError(f"No agent found with the name '{agent_name}'")
|
40
75
|
|
41
76
|
agent = existing_native_agents[0]
|
42
|
-
agent_environments = agent.get("environments", [])
|
77
|
+
agent_environments = agent.get("environments", [])
|
43
78
|
|
44
79
|
is_local = is_local_dev()
|
45
80
|
target_env = env or 'draft'
|
@@ -56,15 +91,37 @@ class ChannelsWebchatController:
|
|
56
91
|
logger.error(f'This agent does not exist in the {env} environment. You need to deploy it to {env} before you can embed the agent')
|
57
92
|
exit(1)
|
58
93
|
|
59
|
-
|
94
|
+
if target_env == 'draft' and is_local == False:
|
95
|
+
logger.error(f'For SAAS, please ensure this agent exists in a Live Environment')
|
96
|
+
exit(1)
|
97
|
+
|
60
98
|
|
61
99
|
|
100
|
+
return filtered_environments[0].get("id")
|
101
|
+
|
62
102
|
def get_tennent_id(self):
|
63
103
|
auth_cfg = Config(AUTH_CONFIG_FILE_FOLDER, AUTH_CONFIG_FILE)
|
64
104
|
|
65
105
|
cfg = Config()
|
66
106
|
active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
|
67
|
-
|
107
|
+
|
108
|
+
existing_auth_config = auth_cfg.get(AUTH_SECTION_HEADER).get(active_env, {})
|
109
|
+
|
110
|
+
existing_token = existing_auth_config.get(AUTH_MCSP_TOKEN_OPT) if existing_auth_config else None
|
111
|
+
token = jwt.decode(existing_token, options={"verify_signature": False})
|
112
|
+
crn = ""
|
113
|
+
crn = token.get('aud', None)
|
114
|
+
|
115
|
+
tenant_id = self.extract_tenant_id_from_crn(crn)
|
116
|
+
return tenant_id
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
def get_tenant_id_local(self):
|
121
|
+
auth_cfg = Config(AUTH_CONFIG_FILE_FOLDER, AUTH_CONFIG_FILE)
|
122
|
+
|
123
|
+
cfg = Config()
|
124
|
+
active_env = cfg.read(CONTEXT_SECTION_HEADER, CONTEXT_ACTIVE_ENV_OPT)
|
68
125
|
|
69
126
|
existing_auth_config = auth_cfg.get(AUTH_SECTION_HEADER).get(active_env, {})
|
70
127
|
|
@@ -72,10 +129,7 @@ class ChannelsWebchatController:
|
|
72
129
|
|
73
130
|
token = jwt.decode(existing_token, options={"verify_signature": False})
|
74
131
|
tenant_id = ""
|
75
|
-
|
76
|
-
tenant_id = token.get('woTenantId', None)
|
77
|
-
else:
|
78
|
-
tenant_id = token.get('tenantId', None)
|
132
|
+
tenant_id = token.get('woTenantId', None)
|
79
133
|
|
80
134
|
return tenant_id
|
81
135
|
|
@@ -99,41 +153,70 @@ class ChannelsWebchatController:
|
|
99
153
|
|
100
154
|
|
101
155
|
def create_webchat_embed_code(self):
|
102
|
-
|
156
|
+
crn = None
|
157
|
+
is_ibm_cloud_env = is_ibm_cloud()
|
158
|
+
is_local = is_local_dev()
|
159
|
+
if is_ibm_cloud_env is True:
|
160
|
+
crn = input("Please enter your CRN which can be gotten from the IBM Cloud UI: ")
|
161
|
+
if crn == "":
|
162
|
+
logger.error("You must enter your CRN for IBM Cloud instances")
|
163
|
+
sys.exit(1)
|
164
|
+
is_crn_correct = self.check_crn_is_correct(crn)
|
165
|
+
if is_crn_correct == False:
|
166
|
+
logger.error("Invalid CRN format provided.")
|
167
|
+
|
168
|
+
if is_ibm_cloud_env and crn is not None:
|
169
|
+
tenant_id = self.extract_tenant_id_from_crn(crn)
|
170
|
+
elif is_ibm_cloud_env is False and is_local is False:
|
171
|
+
tenant_id = self.get_tennent_id()
|
172
|
+
elif is_local:
|
173
|
+
tenant_id = self.get_tenant_id_local()
|
103
174
|
host_url = self.get_host_url()
|
104
175
|
agent_id = self.get_agent_id(self.agent_name)
|
105
176
|
agent_env_id = self.get_environment_id(self.agent_name, self.env)
|
106
177
|
|
107
|
-
is_local = is_local_dev()
|
108
178
|
script_path = (
|
109
179
|
"/wxoLoader.js?embed=true"
|
110
180
|
if is_local
|
111
181
|
else "/wxochat/wxoLoader.js?embed=true"
|
112
182
|
)
|
113
183
|
|
184
|
+
config_lines = [
|
185
|
+
f'orchestrationID: "{tenant_id}"',
|
186
|
+
f'hostURL: "{host_url}"',
|
187
|
+
'rootElementID: "root"',
|
188
|
+
'showLauncher: true',
|
189
|
+
]
|
190
|
+
|
191
|
+
# Conditional fields for IBM Cloud
|
192
|
+
if is_ibm_cloud_env:
|
193
|
+
config_lines.append(f'crn: "{crn}"')
|
194
|
+
if is_ibm_cloud_env:
|
195
|
+
config_lines.append(f'deploymentPlatform: "ibmcloud"')
|
196
|
+
|
197
|
+
config_lines.append(f"""chatOptions: {{
|
198
|
+
agentId: "{agent_id}",
|
199
|
+
agentEnvironmentId: "{agent_env_id}"
|
200
|
+
}}""")
|
201
|
+
|
202
|
+
config_body = ",\n ".join(config_lines)
|
203
|
+
|
114
204
|
script = f"""
|
115
205
|
<script>
|
116
206
|
window.wxOConfiguration = {{
|
117
|
-
|
118
|
-
hostURL: "{host_url}",
|
119
|
-
rootElementID: "root",
|
120
|
-
showLauncher: true,
|
121
|
-
chatOptions: {{
|
122
|
-
agentId: "{agent_id}",
|
123
|
-
agentEnvironmentId: "{agent_env_id}"
|
124
|
-
}},
|
207
|
+
{config_body}
|
125
208
|
}};
|
126
209
|
|
127
210
|
setTimeout(function () {{
|
128
211
|
const script = document.createElement('script');
|
129
212
|
script.src = `${{window.wxOConfiguration.hostURL}}{script_path}`;
|
130
213
|
script.addEventListener('load', function () {{
|
131
|
-
|
214
|
+
wxoLoader.init();
|
132
215
|
}});
|
133
216
|
document.head.appendChild(script);
|
134
217
|
}}, 0);
|
135
218
|
</script>
|
136
|
-
|
219
|
+
"""
|
137
220
|
|
138
221
|
rich.print(script)
|
139
222
|
return script
|
@@ -24,6 +24,8 @@ def chat_start(
|
|
24
24
|
url = "http://localhost:3000/chat-lite"
|
25
25
|
webbrowser.open(url)
|
26
26
|
logger.info(f"Opening chat interface at {url}")
|
27
|
+
# TODO: Remove when connections UI is added
|
28
|
+
logger.warning("When using local chat, requests that the user 'Connect Apps' must be resolved by running `orchestrate connections set-credentials`")
|
27
29
|
else:
|
28
30
|
logger.error("Unable to start orchestrate UI chat service. Please check error messages and logs")
|
29
31
|
|
@@ -191,31 +191,31 @@ def set_credentials_connection_command(
|
|
191
191
|
typer.Option(
|
192
192
|
'--client-id',
|
193
193
|
# help='For oauth_auth_on_behalf_of_flow, oauth_auth_code_flow, oauth_auth_implicit_flow, oauth_auth_password_flow and oauth_auth_client_credentials_flow, the client_id to authenticate against the application token server'
|
194
|
-
help='For oauth_auth_on_behalf_of_flow, the client_id to authenticate against the application token server'
|
194
|
+
help='For oauth_auth_on_behalf_of_flow and oauth_auth_client_credentials_flow, the client_id to authenticate against the application token server'
|
195
|
+
)
|
196
|
+
] = None,
|
197
|
+
client_secret: Annotated[
|
198
|
+
str,
|
199
|
+
typer.Option(
|
200
|
+
'--client-secret',
|
201
|
+
help='For oauth_auth_client_credentials_flow, the client_secret to authenticate with'
|
195
202
|
)
|
196
203
|
] = None,
|
197
|
-
# client_secret: Annotated[
|
198
|
-
# str,
|
199
|
-
# typer.Option(
|
200
|
-
# '--client-secret',
|
201
|
-
# help='For oauth_auth_code_flow, oauth_auth_password_flow and oauth_auth_client_credentials_flow, the client_secret to authenticate with'
|
202
|
-
# )
|
203
|
-
# ] = None,
|
204
204
|
token_url: Annotated[
|
205
205
|
str,
|
206
206
|
typer.Option(
|
207
207
|
'--token-url',
|
208
208
|
# help='For oauth_auth_on_behalf_of_flow, oauth_auth_code_flow, oauth_auth_password_flow and oauth_auth_client_credentials_flow, the url of the application token server'
|
209
|
-
help='For oauth_auth_on_behalf_of_flow, the url of the application token server'
|
209
|
+
help='For oauth_auth_on_behalf_of_flow and oauth_auth_client_credentials_flow, the url of the application token server'
|
210
|
+
)
|
211
|
+
] = None,
|
212
|
+
auth_url: Annotated[
|
213
|
+
str,
|
214
|
+
typer.Option(
|
215
|
+
'--auth-url',
|
216
|
+
help='For oauth_auth_code_flow, the url of the application token server'
|
210
217
|
)
|
211
218
|
] = None,
|
212
|
-
# auth_url: Annotated[
|
213
|
-
# str,
|
214
|
-
# typer.Option(
|
215
|
-
# '--auth-url',
|
216
|
-
# help='For oauth_auth_code_flow, oauth_auth_implicit_flow and oauth_auth_password_flow, the url of the application token server'
|
217
|
-
# )
|
218
|
-
# ] = None,
|
219
219
|
grant_type: Annotated[
|
220
220
|
str,
|
221
221
|
typer.Option(
|
@@ -223,6 +223,13 @@ def set_credentials_connection_command(
|
|
223
223
|
help='For oauth_auth_on_behalf_of_flow, the grant type used by the application token server'
|
224
224
|
)
|
225
225
|
] = None,
|
226
|
+
scopes: Annotated[
|
227
|
+
List[str],
|
228
|
+
typer.Option(
|
229
|
+
'--scopes',
|
230
|
+
help='For oauth_auth_code_flow and oauth_auth_client_credentials_flow, the optional scopes used by the application token server'
|
231
|
+
)
|
232
|
+
] = None,
|
226
233
|
entries: Annotated[
|
227
234
|
List[str],
|
228
235
|
typer.Option(
|
@@ -239,10 +246,11 @@ def set_credentials_connection_command(
|
|
239
246
|
token=token,
|
240
247
|
api_key=api_key,
|
241
248
|
client_id=client_id,
|
242
|
-
|
249
|
+
client_secret=client_secret,
|
243
250
|
token_url=token_url,
|
244
|
-
|
251
|
+
auth_url=auth_url,
|
245
252
|
grant_type=grant_type,
|
253
|
+
scopes=scopes,
|
246
254
|
entries=entries
|
247
255
|
)
|
248
256
|
|
@@ -15,19 +15,19 @@ from ibm_watsonx_orchestrate.agent_builder.connections.types import (
|
|
15
15
|
ConnectionType,
|
16
16
|
IdpConfigData,
|
17
17
|
IdpConfigDataBody,
|
18
|
-
AppConfigData,
|
18
|
+
AppConfigData,
|
19
19
|
BasicAuthCredentials,
|
20
20
|
BearerTokenAuthCredentials,
|
21
21
|
APIKeyAuthCredentials,
|
22
22
|
# OAuth2AuthCodeCredentials,
|
23
|
-
|
23
|
+
OAuth2ClientCredentials,
|
24
24
|
# OAuth2ImplicitCredentials,
|
25
25
|
# OAuth2PasswordCredentials,
|
26
26
|
OAuthOnBehalfOfCredentials,
|
27
27
|
KeyValueConnectionCredentials,
|
28
28
|
CREDENTIALS,
|
29
29
|
IdentityProviderCredentials,
|
30
|
-
OAUTH_CONNECTION_TYPES
|
30
|
+
OAUTH_CONNECTION_TYPES, OAuth2AuthCodeCredentials
|
31
31
|
|
32
32
|
)
|
33
33
|
|
@@ -136,40 +136,31 @@ def _validate_connection_params(type: ConnectionType, **args) -> None:
|
|
136
136
|
f"Missing flags --api-key is required for type {type}"
|
137
137
|
)
|
138
138
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
# if type in (OAUTH_CONNECTION_TYPES.difference({ConnectionType.OAUTH2_IMPLICIT, ConnectionType.OAUTH_ON_BEHALF_OF_FLOW})) and args.get('client_secret') is None:
|
145
|
-
# raise typer.BadParameter(
|
146
|
-
# f"Missing flags --client-secret is required for type {type}"
|
147
|
-
# )
|
148
|
-
|
149
|
-
# if type in (OAUTH_CONNECTION_TYPES.difference({ConnectionType.OAUTH2_IMPLICIT})) and args.get('token_url') is None:
|
150
|
-
# raise typer.BadParameter(
|
151
|
-
# f"Missing flags --token-url is required for type {type}"
|
152
|
-
# )
|
139
|
+
if type in {ConnectionType.OAUTH2_CLIENT_CREDS, ConnectionType.OAUTH2_AUTH_CODE} and args.get('client_secret') is None:
|
140
|
+
raise typer.BadParameter(
|
141
|
+
f"Missing flags --client-secret is required for type {type}"
|
142
|
+
)
|
153
143
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
144
|
+
if type in {ConnectionType.OAUTH2_AUTH_CODE} and args.get('auth_url') is None:
|
145
|
+
raise typer.BadParameter(
|
146
|
+
f"Missing flags --auth-url is required for type {type}"
|
147
|
+
)
|
158
148
|
|
159
|
-
if type
|
149
|
+
if type in {ConnectionType.OAUTH_ON_BEHALF_OF_FLOW, ConnectionType.OAUTH2_CLIENT_CREDS, ConnectionType.OAUTH2_AUTH_CODE} and (
|
160
150
|
args.get('client_id') is None
|
161
151
|
):
|
162
152
|
raise typer.BadParameter(
|
163
153
|
f"Missing flags --client-id is required for type {type}"
|
164
154
|
)
|
165
155
|
|
166
|
-
if type
|
156
|
+
if type in {ConnectionType.OAUTH_ON_BEHALF_OF_FLOW, ConnectionType.OAUTH2_CLIENT_CREDS, ConnectionType.OAUTH2_AUTH_CODE} and (
|
167
157
|
args.get('token_url') is None
|
168
158
|
):
|
169
159
|
raise typer.BadParameter(
|
170
160
|
f"Missing flags --token-url is required for type {type}"
|
171
161
|
)
|
172
162
|
|
163
|
+
|
173
164
|
if type == ConnectionType.OAUTH_ON_BEHALF_OF_FLOW and (
|
174
165
|
args.get('grant_type') is None
|
175
166
|
):
|
@@ -200,19 +191,21 @@ def _get_credentials(type: ConnectionType, **kwargs):
|
|
200
191
|
return APIKeyAuthCredentials(
|
201
192
|
api_key=kwargs.get("api_key")
|
202
193
|
)
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
194
|
+
case ConnectionType.OAUTH2_AUTH_CODE:
|
195
|
+
return OAuth2AuthCodeCredentials(
|
196
|
+
authorization_url=kwargs.get("auth_url"),
|
197
|
+
client_id=kwargs.get("client_id"),
|
198
|
+
client_secret=kwargs.get("client_secret"),
|
199
|
+
token_url=kwargs.get("token_url"),
|
200
|
+
scopes=kwargs.get("scopes")
|
201
|
+
)
|
202
|
+
case ConnectionType.OAUTH2_CLIENT_CREDS:
|
203
|
+
return OAuth2ClientCredentials(
|
204
|
+
client_id=kwargs.get("client_id"),
|
205
|
+
client_secret=kwargs.get("client_secret"),
|
206
|
+
token_url=kwargs.get("token_url"),
|
207
|
+
scopes=kwargs.get("scopes")
|
208
|
+
)
|
216
209
|
# case ConnectionType.OAUTH2_IMPLICIT:
|
217
210
|
# return OAuth2ImplicitCredentials(
|
218
211
|
# authorization_url=kwargs.get("auth_url"),
|
@@ -267,11 +260,14 @@ def add_configuration(config: ConnectionConfiguration) -> None:
|
|
267
260
|
logger.warning(f"Detected a change in sso from '{existing_configuration.sso}' to '{config.sso}'. The associated credentials will be removed.")
|
268
261
|
should_delete_credentials = True
|
269
262
|
|
263
|
+
existing_conn_type = get_connection_type(security_scheme=existing_configuration.security_scheme, auth_type=existing_configuration.auth_type)
|
264
|
+
use_app_credentials = existing_conn_type in OAUTH_CONNECTION_TYPES
|
265
|
+
|
270
266
|
if should_delete_credentials:
|
271
267
|
try:
|
272
|
-
existing_credentials = client.get_credentials(app_id=app_id, env=environment,
|
268
|
+
existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_app_credentials=use_app_credentials)
|
273
269
|
if existing_credentials:
|
274
|
-
client.delete_credentials(app_id=app_id, env=environment,
|
270
|
+
client.delete_credentials(app_id=app_id, env=environment, use_app_credentials=use_app_credentials)
|
275
271
|
except:
|
276
272
|
logger.error(f"Error removing credentials for connection '{app_id}' in environment '{environment}'. No changes have been made to the configuration.")
|
277
273
|
sys.exit(1)
|
@@ -289,11 +285,11 @@ def add_configuration(config: ConnectionConfiguration) -> None:
|
|
289
285
|
logger.error(response_text)
|
290
286
|
exit(1)
|
291
287
|
|
292
|
-
def add_credentials(app_id: str, environment: ConnectionEnvironment,
|
288
|
+
def add_credentials(app_id: str, environment: ConnectionEnvironment, use_app_credentials: bool, credentials: CREDENTIALS) -> None:
|
293
289
|
client = get_connections_client()
|
294
290
|
try:
|
295
|
-
existing_credentials = client.get_credentials(app_id=app_id, env=environment,
|
296
|
-
if
|
291
|
+
existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_app_credentials=use_app_credentials)
|
292
|
+
if use_app_credentials:
|
297
293
|
payload = {
|
298
294
|
"app_credentials": credentials.model_dump(exclude_none=True)
|
299
295
|
}
|
@@ -304,9 +300,9 @@ def add_credentials(app_id: str, environment: ConnectionEnvironment, use_sso: bo
|
|
304
300
|
|
305
301
|
logger.info(f"Setting credentials for environment '{environment}' on connection '{app_id}'")
|
306
302
|
if existing_credentials:
|
307
|
-
client.update_credentials(app_id=app_id, env=environment,
|
303
|
+
client.update_credentials(app_id=app_id, env=environment, use_app_credentials=use_app_credentials, payload=payload)
|
308
304
|
else:
|
309
|
-
client.create_credentials(app_id=app_id,env=environment,
|
305
|
+
client.create_credentials(app_id=app_id,env=environment, use_app_credentials=use_app_credentials, payload=payload)
|
310
306
|
logger.info(f"Credentials successfully set for '{environment}' environment of connection '{app_id}'")
|
311
307
|
except requests.HTTPError as e:
|
312
308
|
response = e.response
|
@@ -318,7 +314,7 @@ def add_identity_provider(app_id: str, environment: ConnectionEnvironment, idp:
|
|
318
314
|
client = get_connections_client()
|
319
315
|
|
320
316
|
try:
|
321
|
-
existing_credentials = client.get_credentials(app_id=app_id, env=environment,
|
317
|
+
existing_credentials = client.get_credentials(app_id=app_id, env=environment, use_app_credentials=True)
|
322
318
|
|
323
319
|
payload = {
|
324
320
|
"idp_credentials": idp.model_dump()
|
@@ -326,9 +322,9 @@ def add_identity_provider(app_id: str, environment: ConnectionEnvironment, idp:
|
|
326
322
|
|
327
323
|
logger.info(f"Setting identity provider for environment '{environment}' on connection '{app_id}'")
|
328
324
|
if existing_credentials:
|
329
|
-
client.update_credentials(app_id=app_id, env=environment,
|
325
|
+
client.update_credentials(app_id=app_id, env=environment, use_app_credentials=True, payload=payload)
|
330
326
|
else:
|
331
|
-
client.create_credentials(app_id=app_id,env=environment,
|
327
|
+
client.create_credentials(app_id=app_id,env=environment, use_app_credentials=True, payload=payload)
|
332
328
|
logger.info(f"Identity provider successfully set for '{environment}' environment of connection '{app_id}'")
|
333
329
|
except requests.HTTPError as e:
|
334
330
|
response = e.response
|
@@ -350,7 +346,7 @@ def add_connection(app_id: str) -> None:
|
|
350
346
|
status_code = response.status_code
|
351
347
|
try:
|
352
348
|
if status_code == 409:
|
353
|
-
response_text = f"Failed to create connection. A connection with the App ID '{app_id}' already exists. Please select a
|
349
|
+
response_text = f"Failed to create connection. A connection with the App ID '{app_id}' already exists. Please select a different App ID or delete the existing resource."
|
354
350
|
else:
|
355
351
|
resp = json.loads(response_text)
|
356
352
|
response_text = resp.get('detail')
|
@@ -374,12 +370,14 @@ def remove_connection(app_id: str) -> None:
|
|
374
370
|
|
375
371
|
def list_connections(environment: ConnectionEnvironment | None, verbose: bool = False) -> None:
|
376
372
|
client = get_connections_client()
|
377
|
-
|
378
373
|
connections = client.list()
|
379
|
-
|
374
|
+
is_local = is_local_dev()
|
375
|
+
|
380
376
|
if verbose:
|
381
377
|
connections_list = []
|
382
378
|
for conn in connections:
|
379
|
+
if is_local and conn.environment == ConnectionEnvironment.LIVE:
|
380
|
+
continue
|
383
381
|
connections_list.append(json.loads(conn.model_dump_json()))
|
384
382
|
|
385
383
|
rich.print_json(json.dumps(connections_list, indent=4))
|
@@ -387,11 +385,17 @@ def list_connections(environment: ConnectionEnvironment | None, verbose: bool =
|
|
387
385
|
non_configured_table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True, title="*Non-Configured")
|
388
386
|
draft_table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True, title="Draft")
|
389
387
|
live_table = rich.table.Table(show_header=True, header_style="bold white", show_lines=True, title="Live")
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
388
|
+
default_args = {"justify": "center", "no_wrap": True}
|
389
|
+
column_args = {
|
390
|
+
"App ID": {"overflow": "fold"},
|
391
|
+
"Auth Type": {},
|
392
|
+
"Type": {},
|
393
|
+
"Credentials Set/ Connected": {}
|
394
|
+
}
|
395
|
+
for column in column_args:
|
396
|
+
draft_table.add_column(column,**default_args, **column_args[column])
|
397
|
+
live_table.add_column(column,**default_args, **column_args[column])
|
398
|
+
non_configured_table.add_column(column,**default_args, **column_args[column])
|
395
399
|
|
396
400
|
for conn in connections:
|
397
401
|
if conn.environment is None:
|
@@ -412,7 +416,7 @@ def list_connections(environment: ConnectionEnvironment | None, verbose: bool =
|
|
412
416
|
conn.preference,
|
413
417
|
"✅" if conn.credentials_entered else "❌"
|
414
418
|
)
|
415
|
-
elif conn.environment == ConnectionEnvironment.LIVE:
|
419
|
+
elif conn.environment == ConnectionEnvironment.LIVE and not is_local:
|
416
420
|
live_table.add_row(
|
417
421
|
conn.app_id,
|
418
422
|
connection_type,
|
@@ -463,11 +467,6 @@ def configure_connection(**kwargs) -> None:
|
|
463
467
|
|
464
468
|
config = ConnectionConfiguration.model_validate(kwargs)
|
465
469
|
|
466
|
-
# TODO: Remove once Oauth is supported on local
|
467
|
-
if config.security_scheme == ConnectionSecurityScheme.OAUTH2 and is_local_dev():
|
468
|
-
logger.error("Use of OAuth connections unsupported for local development at this time.")
|
469
|
-
sys.exit(1)
|
470
|
-
|
471
470
|
add_configuration(config)
|
472
471
|
|
473
472
|
def set_credentials_connection(
|
@@ -484,11 +483,12 @@ def set_credentials_connection(
|
|
484
483
|
|
485
484
|
sso_enabled = config.sso
|
486
485
|
conn_type = get_connection_type(security_scheme=config.security_scheme, auth_type=config.auth_type)
|
486
|
+
use_app_credentials = conn_type in OAUTH_CONNECTION_TYPES
|
487
487
|
|
488
488
|
_validate_connection_params(type=conn_type, **kwargs)
|
489
489
|
credentials = _get_credentials(type=conn_type, **kwargs)
|
490
490
|
|
491
|
-
add_credentials(app_id=app_id, environment=environment,
|
491
|
+
add_credentials(app_id=app_id, environment=environment, use_app_credentials=use_app_credentials, credentials=credentials)
|
492
492
|
|
493
493
|
def set_identity_provider_connection(
|
494
494
|
app_id: str,
|
@@ -167,7 +167,7 @@ def activate(name: str, apikey: str=None, username: str=None, password: str=None
|
|
167
167
|
|
168
168
|
def add(name: str, url: str, should_activate: bool=False, iam_url: str=None, type: EnvironmentAuthType=None, insecure: bool=None, verify: str=None) -> None:
|
169
169
|
if name == PROTECTED_ENV_NAME:
|
170
|
-
logger.error(f"The name '{PROTECTED_ENV_NAME}' is a reserved environment name. Please select a
|
170
|
+
logger.error(f"The name '{PROTECTED_ENV_NAME}' is a reserved environment name. Please select a different name or use `orchestrate env activate {PROTECTED_ENV_NAME}` to swap to '{PROTECTED_ENV_NAME}'")
|
171
171
|
return
|
172
172
|
|
173
173
|
cfg = Config()
|