Coverage for apps/integrations/resolver.py: 92%

28 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-11-04 14:06 +0000

1"""Credential resolution (design D3): user creds -> org creds -> platform/env default. 

2 

3Returns the resolved provider + decrypted secret for a category, or None when nothing is 

4configured beyond the dev default — callers then fall back to the dev stub, so local/dev and the 

5existing credit/AUS suites keep working. 

6""" 

7 

8from __future__ import annotations 

9 

10from dataclasses import dataclass, field 

11 

12from django.conf import settings 

13 

14from apps.integrations.catalog import providers_by_category 

15from apps.integrations.encryption import decrypt_secret 

16from apps.integrations.models import OrgIntegration, UserCredential 

17 

18# Env var that holds the platform-default provider for a category (the dev fallback). 

19_ENV_DEFAULT_SETTING = {"credit": "CREDIT_PROVIDER", "aus": "AUS_ENGINE"} 

20 

21 

22@dataclass(frozen=True) 

23class ResolvedCredential: 

24 provider: str 

25 scope: str # "user" | "org" | "platform" 

26 config: dict = field(default_factory=dict) 

27 secret: str | None = None 

28 

29 

30def resolve_credentials(category: str, user=None, org=None) -> ResolvedCredential | None: 

31 codes = [p.code for p in providers_by_category(category)] 

32 

33 if user is not None and codes: 

34 uc = UserCredential.objects.filter(user=user, provider__in=codes).first() 

35 if uc is not None: 35 ↛ 38line 35 didn't jump to line 38 because the condition on line 35 was always true

36 return ResolvedCredential(uc.provider, "user", uc.config, decrypt_secret(uc.secret_enc)) 

37 

38 if org is not None and codes: 

39 oi = ( 

40 OrgIntegration.objects.filter(org_unit=org, provider__in=codes, enabled=True).first() 

41 ) 

42 if oi is not None: 

43 return ResolvedCredential(oi.provider, "org", oi.config, decrypt_secret(oi.secret_enc)) 

44 

45 env_setting = _ENV_DEFAULT_SETTING.get(category) 

46 provider = getattr(settings, env_setting, "dev") if env_setting else "dev" 

47 if provider and provider != "dev": 47 ↛ 48line 47 didn't jump to line 48 because the condition on line 47 was never true

48 return ResolvedCredential(provider, "platform", {}, None) 

49 return None