Skip to content

Commit 8e7151f

Browse files
CopilotCataldir
andauthored
[WIP] Implement multi-tenant connector configuration (#133)
* Initial plan * feat: implement multi-tenant connector configuration * fix: harden tenant resolver input validation * chore(lint): align import order and formatting for CI --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Ricardo Cataldi <rcataldi@microsoft.com>
1 parent f78d278 commit 8e7151f

File tree

13 files changed

+848
-12
lines changed

13 files changed

+848
-12
lines changed
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Event consumers for background processing."""
22

3-
from crud_service.consumers.connector_sync import ConnectorSyncConsumer
4-
from crud_service.consumers.connector_sync import get_connector_sync_consumer
3+
from crud_service.consumers.connector_sync import ConnectorSyncConsumer, get_connector_sync_consumer
54

65
__all__ = ["ConnectorSyncConsumer", "get_connector_sync_consumer"]

apps/crud-service/src/crud_service/consumers/connector_sync.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,9 @@ async def on_event(partition_context, event): # noqa: ANN001
174174
await partition_context.update_checkpoint(event)
175175

176176
async def on_error(partition_context, error): # noqa: ANN001
177-
logger.error("connector_sync_consumer_error partition=%s error=%s", partition_context, error)
177+
logger.error(
178+
"connector_sync_consumer_error partition=%s error=%s", partition_context, error
179+
)
178180

179181
try:
180182
async with self._consumer:

apps/crud-service/src/crud_service/routes/connector_webhooks.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ async def replay_dead_letter(dead_letter_id: str):
3434

3535
replayed = await connector_sync_consumer.replay_dead_letter(dead_letter_id)
3636
if not replayed:
37-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Dead-letter event not found")
37+
raise HTTPException(
38+
status_code=status.HTTP_404_NOT_FOUND, detail="Dead-letter event not found"
39+
)
3840

3941
return {"status": "replayed", "dead_letter_id": dead_letter_id}
4042

docs/IMPLEMENTATION_ROADMAP.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,11 @@ This document tracks the implementation progress of the Holiday Peak Hub platfor
514514
**Issue**: [#81](https://github.com/Azure-Samples/holiday-peak-hub/issues/81)
515515

516516
**Tasks**:
517-
- [ ] Design tenant configuration schema
518-
- [ ] Implement TenantResolver middleware
519-
- [ ] Add Azure Key Vault integration for secrets
520-
- [ ] Create connector instance caching
521-
- [ ] Document multi-tenant setup
517+
- [x] Design tenant configuration schema
518+
- [x] Implement TenantResolver middleware
519+
- [x] Add Azure Key Vault integration for secrets
520+
- [x] Create connector instance caching
521+
- [x] Document multi-tenant setup
522522

523523
#### 8.5 Internal Data Guardrails
524524
**Priority**: CRITICAL

docs/architecture/components/libs/integrations.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,22 @@ When adding any new connector under `lib/src/holiday_peak_lib/integrations/`:
5151
- Auth: bearer, basic, api_key, oauth2 (pre-fetched token).
5252
- Operations: get/list/search products, fetch categories, fetch product assets, push enrichment.
5353
- Resilience: token-bucket rate limit + exponential retry for 429/5xx and transport errors.
54+
55+
## Multi-Tenant Connector Configuration
56+
57+
`holiday_peak_lib.connectors` provides tenant-aware connector configuration and resolution:
58+
59+
- `tenant_config.py`
60+
- `TenantConfigStore` loads per-tenant files from `connectors/config/tenant-{tenantId}.yaml`.
61+
- Supports environment variable overrides per connector/domain.
62+
- Resolves Azure Key Vault references for tenant-isolated secrets.
63+
64+
- `tenant_resolver.py`
65+
- `TenantResolver` resolves tenant context from request headers/query/default.
66+
- `TenantContextMiddleware` propagates tenant context through request state and async context.
67+
- `TenantConnectorResolver` caches connector instances by tenant/domain/vendor pool key.
68+
69+
Recommended env override format:
70+
71+
- `TENANT_<TENANT_ID>_CONNECTOR_<DOMAIN>_<SETTING>=value`
72+
- `CONNECTOR_<DOMAIN>_<SETTING>=value`

lib/src/holiday_peak_lib/connectors/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,37 @@
77
ConnectorRegistry,
88
default_registry,
99
)
10+
from holiday_peak_lib.connectors.tenant_config import (
11+
ConnectorRuntimeConfig,
12+
KeyVaultSecretResolver,
13+
TenantConfig,
14+
TenantConfigStore,
15+
TenantConnectorConfig,
16+
normalize_tenant_id,
17+
)
18+
from holiday_peak_lib.connectors.tenant_resolver import (
19+
TenantConnectorResolver,
20+
TenantContext,
21+
TenantContextMiddleware,
22+
TenantResolver,
23+
get_current_tenant_context,
24+
)
1025

1126
__all__ = [
1227
"ConnectorDefinition",
1328
"ConnectorHealth",
1429
"ConnectorRegistration",
1530
"ConnectorRegistry",
31+
"ConnectorRuntimeConfig",
32+
"KeyVaultSecretResolver",
33+
"TenantConfig",
34+
"TenantConfigStore",
35+
"TenantConnectorConfig",
36+
"normalize_tenant_id",
37+
"TenantConnectorResolver",
38+
"TenantContext",
39+
"TenantContextMiddleware",
40+
"TenantResolver",
41+
"get_current_tenant_context",
1642
"default_registry",
1743
]

0 commit comments

Comments
 (0)