Skip to content

Commit 69e6ed2

Browse files
authored
Merge branch 'main' into fix/daft-analytics
2 parents b59ad48 + f2648a1 commit 69e6ed2

File tree

18 files changed

+164
-106
lines changed

18 files changed

+164
-106
lines changed

.env.example

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,18 @@ ATLAN_START_TO_CLOSE_TIMEOUT_SECONDS=7200 # 2 hours
2424
# if you plan to deploy the app in customer environment, below is a sample environment variables you need to set
2525
ATLAN_WORKFLOW_HOST="tenant-temporal.atlan.com"
2626
ATLAN_WORKFLOW_PORT="443"
27-
ATLAN_WORKFLOW_AUTH_ENABLED="true"
27+
ATLAN_AUTH_ENABLED="true"
28+
ATLAN_AUTH_URL="https://tenant.atlan.com/auth/realms/default/protocol/openid-connect/token"
29+
ATLAN_WORKFLOW_TLS_ENABLED="true"
2830
ENABLE_ATLAN_UPLOAD="true"
29-
ATLAN_DEPLOYMENT_SECRETS='{"appName_app_client_id":"enter_client_id","appName_app_client_secret":"enter_secret","atlan_auth_url":"https://tenant.atlan.com/auth/realms/default/protocol/openid-connect/token","workflow_tls_enabled":"true","deployment_name":"agent-v2"}'
3031

3132
# Storage:
3233
DEPLOYMENT_OBJECT_STORE_NAME="objectstore"
33-
UPSTREAM_OBJECT_STORE_NAME="atlan-storage"
34+
UPSTREAM_OBJECT_STORE_NAME="atlan-objectstore"
3435

3536
# Secret Store
36-
SECRET_STORE_NAME="aws-secrets"
37+
SECRET_STORE_NAME="aws-secrets"
38+
39+
# Client ID/Secret key fields, the value is the name of the key in the secret store
40+
ATLAN_AUTH_CLIENT_ID_KEY="ATLAN_AUTH_CLIENT_ID"
41+
ATLAN_AUTH_CLIENT_SECRET_KEY="ATLAN_AUTH_CLIENT_SECRET"

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## v0.1.1rc63 (November 12, 2025)
4+
5+
Full Changelog: https://github.com/atlanhq/application-sdk/compare/v0.1.1rc62...v0.1.1rc63
6+
7+
### Features
8+
9+
- handle single key secret stores (#812) (by @nishantmunjal7 in [abf5f6d](https://github.com/atlanhq/application-sdk/commit/abf5f6d))
10+
- deployment secret single-key (#816) (by @nishantmunjal7 in [c5efd9a](https://github.com/atlanhq/application-sdk/commit/c5efd9a))
11+
12+
313
## v0.1.1rc62 (November 03, 2025)
414

515
Full Changelog: https://github.com/atlanhq/application-sdk/compare/v0.1.1rc61...v0.1.1rc62

application_sdk/clients/atlan_auth.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
"""OAuth2 token manager with automatic secret store discovery."""
22

33
import time
4-
from typing import Any, Dict, Optional
4+
from typing import Dict, Optional
55

66
import aiohttp
77

88
from application_sdk.common.error_codes import ClientError
99
from application_sdk.constants import (
1010
APPLICATION_NAME,
11+
AUTH_ENABLED,
12+
AUTH_URL,
1113
WORKFLOW_AUTH_CLIENT_ID_KEY,
1214
WORKFLOW_AUTH_CLIENT_SECRET_KEY,
13-
WORKFLOW_AUTH_ENABLED,
14-
WORKFLOW_AUTH_URL_KEY,
1515
)
1616
from application_sdk.observability.logger_adaptor import get_logger
1717
from application_sdk.services.secretstore import SecretStore
@@ -39,9 +39,8 @@ def __init__(self):
3939
(environment variables, AWS Secrets Manager, Azure Key Vault, etc.)
4040
"""
4141
self.application_name = APPLICATION_NAME
42-
self.auth_config: Dict[str, Any] = SecretStore.get_deployment_secret()
43-
self.auth_enabled: bool = WORKFLOW_AUTH_ENABLED
44-
self.auth_url: Optional[str] = None
42+
self.auth_enabled: bool = AUTH_ENABLED
43+
self.auth_url: Optional[str] = AUTH_URL
4544

4645
# Secret store credentials (cached after first fetch)
4746
self.credentials: Optional[Dict[str, str]] = None
@@ -175,18 +174,17 @@ def get_time_until_expiry(self) -> Optional[float]:
175174

176175
async def _extract_auth_credentials(self) -> Optional[Dict[str, str]]:
177176
"""Fetch app credentials from secret store - auth-specific logic"""
178-
if (
179-
WORKFLOW_AUTH_CLIENT_ID_KEY in self.auth_config
180-
and WORKFLOW_AUTH_CLIENT_SECRET_KEY in self.auth_config
181-
):
177+
client_id = SecretStore.get_deployment_secret(WORKFLOW_AUTH_CLIENT_ID_KEY)
178+
client_secret = SecretStore.get_deployment_secret(
179+
WORKFLOW_AUTH_CLIENT_SECRET_KEY
180+
)
181+
182+
if client_id and client_secret:
182183
credentials = {
183-
"client_id": self.auth_config[WORKFLOW_AUTH_CLIENT_ID_KEY],
184-
"client_secret": self.auth_config[WORKFLOW_AUTH_CLIENT_SECRET_KEY],
184+
"client_id": client_id,
185+
"client_secret": client_secret,
185186
}
186187

187-
if WORKFLOW_AUTH_URL_KEY in self.auth_config:
188-
self.auth_url = self.auth_config[WORKFLOW_AUTH_URL_KEY]
189-
190188
return credentials
191189
return None
192190

@@ -199,10 +197,8 @@ def clear_cache(self) -> None:
199197
"""
200198
# we are doing this to force a fetch of the credentials from secret store
201199
self.credentials = None
202-
self.auth_url = None
203200
self._access_token = None
204201
self._token_expiry = 0
205-
self.auth_config = {}
206202

207203
def calculate_refresh_interval(self) -> int:
208204
"""Calculate the optimal token refresh interval based on token expiry.

application_sdk/clients/temporal.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@
1818
from application_sdk.constants import (
1919
APPLICATION_NAME,
2020
DEPLOYMENT_NAME,
21-
DEPLOYMENT_NAME_KEY,
2221
IS_LOCKING_DISABLED,
2322
MAX_CONCURRENT_ACTIVITIES,
2423
WORKFLOW_HOST,
2524
WORKFLOW_MAX_TIMEOUT_HOURS,
2625
WORKFLOW_NAMESPACE,
2726
WORKFLOW_PORT,
28-
WORKFLOW_TLS_ENABLED_KEY,
27+
WORKFLOW_TLS_ENABLED,
2928
)
3029
from application_sdk.events.models import (
3130
ApplicationEventNames,
@@ -97,7 +96,6 @@ def __init__(
9796
self.port = port if port else WORKFLOW_PORT
9897
self.namespace = namespace if namespace else WORKFLOW_NAMESPACE
9998

100-
self.deployment_config: Dict[str, Any] = SecretStore.get_deployment_secret()
10199
self.worker_task_queue = self.get_worker_task_queue()
102100
self.auth_manager = AtlanAuthClient()
103101

@@ -118,12 +116,8 @@ def get_worker_task_queue(self) -> str:
118116
Returns:
119117
str: The task queue name in format "app_name-deployment_name".
120118
"""
121-
deployment_name = self.deployment_config.get(
122-
DEPLOYMENT_NAME_KEY, DEPLOYMENT_NAME
123-
)
124-
125-
if deployment_name:
126-
return f"atlan-{self.application_name}-{deployment_name}"
119+
if DEPLOYMENT_NAME:
120+
return f"atlan-{self.application_name}-{DEPLOYMENT_NAME}"
127121
else:
128122
return self.application_name
129123

@@ -228,12 +222,9 @@ async def load(self) -> None:
228222
connection_options: Dict[str, Any] = {
229223
"target_host": self.get_connection_string(),
230224
"namespace": self.namespace,
231-
"tls": False,
225+
"tls": WORKFLOW_TLS_ENABLED,
232226
}
233227

234-
connection_options["tls"] = self.deployment_config.get(
235-
WORKFLOW_TLS_ENABLED_KEY, False
236-
)
237228
self.worker_task_queue = self.get_worker_task_queue()
238229

239230
if self.auth_manager.auth_enabled:

application_sdk/constants.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,23 @@
105105
DEPLOYMENT_SECRET_PATH = os.getenv(
106106
"ATLAN_DEPLOYMENT_SECRET_PATH", "ATLAN_DEPLOYMENT_SECRETS"
107107
)
108-
WORKFLOW_AUTH_ENABLED = (
109-
os.getenv("ATLAN_WORKFLOW_AUTH_ENABLED", "false").lower() == "true"
108+
AUTH_ENABLED = os.getenv("ATLAN_AUTH_ENABLED", "false").lower() == "true"
109+
#: OAuth2 authentication URL for workflow services
110+
AUTH_URL = os.getenv("ATLAN_AUTH_URL")
111+
#: Whether to enable TLS for Temporal workflow connections
112+
WORKFLOW_TLS_ENABLED = (
113+
os.getenv("ATLAN_WORKFLOW_TLS_ENABLED", "false").lower() == "true"
110114
)
111115

112116
# Deployment Secret Store Key Names
113-
WORKFLOW_AUTH_CLIENT_ID_KEY = f"{APPLICATION_NAME}_app_client_id"
114-
WORKFLOW_AUTH_CLIENT_SECRET_KEY = f"{APPLICATION_NAME}_app_client_secret"
115-
WORKFLOW_AUTH_URL_KEY = "atlan_auth_url"
116-
WORKFLOW_TLS_ENABLED_KEY = "workflow_tls_enabled"
117-
DEPLOYMENT_NAME_KEY = "deployment_name"
117+
#: Key name for OAuth2 client ID in deployment secrets (can be overridden via ATLAN_AUTH_CLIENT_ID_KEY)
118+
WORKFLOW_AUTH_CLIENT_ID_KEY = os.getenv(
119+
"ATLAN_AUTH_CLIENT_ID_KEY", "ATLAN_AUTH_CLIENT_ID"
120+
)
121+
#: Key name for OAuth2 client secret in deployment secrets (can be overridden via ATLAN_AUTH_CLIENT_SECRET_KEY)
122+
WORKFLOW_AUTH_CLIENT_SECRET_KEY = os.getenv(
123+
"ATLAN_AUTH_CLIENT_SECRET_KEY", "ATLAN_AUTH_CLIENT_SECRET"
124+
)
118125

119126
# Workflow Constants
120127
#: Timeout duration for activity heartbeats

application_sdk/events/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class WorkerStartEventData(BaseModel):
155155
156156
Attributes:
157157
application_name: Name of the application the worker belongs to.
158+
deployment_name: Name of the deployment the worker belongs to.
158159
task_queue: Task queue name for the worker.
159160
namespace: Temporal namespace for the worker.
160161
host: Host address of the Temporal server.
@@ -167,6 +168,7 @@ class WorkerStartEventData(BaseModel):
167168

168169
version: str = WORKER_START_EVENT_VERSION
169170
application_name: str
171+
deployment_name: str
170172
task_queue: str
171173
namespace: str
172174
host: str

application_sdk/services/secretstore.py

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -235,41 +235,59 @@ def resolve_credentials(
235235
return credentials
236236

237237
@classmethod
238-
def get_deployment_secret(cls) -> Dict[str, Any]:
239-
"""Get deployment configuration from the deployment secret store.
238+
def get_deployment_secret(cls, key: str) -> Any:
239+
"""Get a specific key from deployment configuration in the deployment secret store.
240240
241241
Validates that the deployment secret store component is registered
242242
before attempting to fetch secrets to prevent errors. This method
243-
is commonly used to retrieve environment-specific configuration.
243+
fetches only the specified key from the deployment secret, rather than
244+
the entire secret dictionary.
245+
246+
Args:
247+
key (str): The key to fetch from the deployment secret.
244248
245249
Returns:
246-
Dict[str, Any]: Deployment configuration data, or empty dict if
247-
component is unavailable or fetch fails.
250+
Any: The value for the specified key, or None if the key is not found
251+
or the component is unavailable.
248252
249253
Examples:
250-
>>> # Get deployment configuration
251-
>>> config = SecretStore.get_deployment_secret()
252-
>>> if config:
253-
... print(f"Environment: {config.get('environment')}")
254-
... print(f"Region: {config.get('region')}")
255-
>>> else:
256-
... print("No deployment configuration available")
257-
>>> # Use in application initialization
258-
>>> deployment_config = SecretStore.get_deployment_secret()
259-
>>> if deployment_config.get('debug_mode'):
260-
... logging.getLogger().setLevel(logging.DEBUG)
254+
>>> # Get a specific deployment configuration value
255+
>>> auth_url = SecretStore.get_deployment_secret("ATLAN_AUTH_CLIENT_ID")
256+
>>> if auth_url:
257+
... print(f"Auth URL: {auth_url}")
258+
>>> # Get deployment name
259+
>>> deployment_name = SecretStore.get_deployment_secret("deployment_name")
260+
>>> if deployment_name:
261+
... print(f"Deployment: {deployment_name}")
261262
"""
262263
if not is_component_registered(DEPLOYMENT_SECRET_STORE_NAME):
263264
logger.warning(
264265
f"Deployment secret store component '{DEPLOYMENT_SECRET_STORE_NAME}' not registered."
265266
)
266-
return {}
267+
return None
267268

268269
try:
269-
return cls.get_secret(DEPLOYMENT_SECRET_PATH, DEPLOYMENT_SECRET_STORE_NAME)
270+
secret_data = cls.get_secret(
271+
DEPLOYMENT_SECRET_PATH, DEPLOYMENT_SECRET_STORE_NAME
272+
)
273+
if isinstance(secret_data, dict) and key in secret_data:
274+
return secret_data[key]
275+
276+
logger.debug(f"Multi-key not found, checking single-key secret for '{key}'")
277+
single_secret_data = cls.get_secret(key, DEPLOYMENT_SECRET_STORE_NAME)
278+
if isinstance(single_secret_data, dict):
279+
# Handle both {key:value} and {"value": "..."} cases
280+
if key in single_secret_data:
281+
return single_secret_data[key]
282+
elif len(single_secret_data) == 1:
283+
# extract single value
284+
return list(single_secret_data.values())[0]
285+
286+
return None
287+
270288
except Exception as e:
271-
logger.error(f"Failed to fetch deployment config: {e}")
272-
return {}
289+
logger.error(f"Failed to fetch deployment config key '{key}': {e}")
290+
return None
273291

274292
@classmethod
275293
def get_secret(

application_sdk/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
Version information for the application_sdk package.
33
"""
44

5-
__version__ = "0.1.1rc62"
5+
__version__ = "0.1.1rc63"

application_sdk/worker.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from temporalio.worker import Worker as TemporalWorker
1515

1616
from application_sdk.clients.workflow import WorkflowClient
17-
from application_sdk.constants import MAX_CONCURRENT_ACTIVITIES
17+
from application_sdk.constants import DEPLOYMENT_NAME, MAX_CONCURRENT_ACTIVITIES
1818
from application_sdk.events.models import (
1919
ApplicationEventNames,
2020
Event,
@@ -122,6 +122,7 @@ def __init__(
122122
if self.workflow_client:
123123
self._worker_creation_event_data = WorkerStartEventData(
124124
application_name=self.workflow_client.application_name,
125+
deployment_name=DEPLOYMENT_NAME,
125126
task_queue=self.workflow_client.worker_task_queue,
126127
namespace=self.workflow_client.namespace,
127128
host=self.workflow_client.host,

components/atlan-storage.yaml

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
apiVersion: dapr.io/v1alpha1
22
kind: Component
33
metadata:
4-
name: atlan-storage
4+
name: atlan-objectstore
55
spec:
6-
version: v1
76
type: bindings.aws.s3
8-
ignoreErrors: true
7+
version: v1
98
metadata:
9+
- name: bucket
10+
value: atlan-bucket
11+
- name: region
12+
value: us-east-1
13+
- name: endpoint
14+
value: https://{{tenant}}.atlan.com/api/blobstorage
1015
- name: accessKey
11-
value: "{{clientId}}"
16+
secretKeyRef:
17+
name: ATLAN_AUTH_CLIENT_ID
18+
key: ATLAN_AUTH_CLIENT_ID
1219
- name: secretKey
13-
value: "{{clientSecret}}"
14-
- name: endpoint
15-
value: "https://{{tenant}}.atlan.com/api/blobstorage"
16-
- name: bucket
17-
value: "atlan-default-bucket"
20+
secretKeyRef:
21+
name: ATLAN_AUTH_CLIENT_SECRET
22+
key: ATLAN_AUTH_CLIENT_SECRET
1823
- name: forcePathStyle
1924
value: "true"
20-
- name: region
21-
value: "us-east-1"
25+
auth:
26+
secretStore: deployment-secret-store

0 commit comments

Comments
 (0)