feat(azure-foundry): add Microsoft Entra ID auth
Use azure-identity DefaultAzureCredential for keyless Foundry auth. Preserve refreshable callable credentials through OpenAI and Anthropic client paths. Add setup, doctor, auth status, docs, and tests for Entra auth. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
Teknium
co-authored by
Copilot
parent
457fa913b8
commit
9df9816dab
@@ -566,6 +566,54 @@ def _interactive_auth() -> None:
|
||||
print()
|
||||
except ImportError:
|
||||
pass # boto3 or bedrock_adapter not available
|
||||
|
||||
# Show Azure Foundry Entra ID status
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
_cfg = load_config()
|
||||
_model_cfg = _cfg.get("model") if isinstance(_cfg, dict) else None
|
||||
if isinstance(_model_cfg, dict):
|
||||
_cfg_provider = str(_model_cfg.get("provider") or "").strip().lower()
|
||||
_cfg_auth_mode = str(_model_cfg.get("auth_mode") or "").strip().lower()
|
||||
if _cfg_provider == "azure-foundry" and _cfg_auth_mode == "entra_id":
|
||||
from agent.azure_identity_adapter import (
|
||||
EntraIdentityConfig,
|
||||
SCOPE_AI_AZURE_DEFAULT,
|
||||
describe_active_credential,
|
||||
has_azure_identity_installed,
|
||||
)
|
||||
_base_url = str(_model_cfg.get("base_url") or "").strip()
|
||||
_entra = _model_cfg.get("entra") or {}
|
||||
if not isinstance(_entra, dict):
|
||||
_entra = {}
|
||||
_scope = (
|
||||
str(_entra.get("scope") or "").strip()
|
||||
or SCOPE_AI_AZURE_DEFAULT
|
||||
)
|
||||
print(f"azure-foundry (Microsoft Entra ID):")
|
||||
print(f" Endpoint: {_base_url or '(not configured)'}")
|
||||
print(f" Scope: {_scope}")
|
||||
if not has_azure_identity_installed():
|
||||
print(" Status: ⚠ azure-identity not installed "
|
||||
"(pip install azure-identity)")
|
||||
else:
|
||||
_entra_cfg = EntraIdentityConfig(
|
||||
scope=_scope,
|
||||
)
|
||||
_info = describe_active_credential(config=_entra_cfg, timeout_seconds=10.0)
|
||||
_env_sources = _info.get("env_sources") or []
|
||||
if _info.get("ok"):
|
||||
_tag = ", ".join(_env_sources) if _env_sources else "default chain"
|
||||
print(f" Status: ✓ token acquired ({_tag})")
|
||||
else:
|
||||
_err = _info.get("error") or "credential chain exhausted"
|
||||
print(f" Status: ⚠ {_err}")
|
||||
_hint = _info.get("hint")
|
||||
if _hint:
|
||||
print(f" Hint: {_hint}")
|
||||
print()
|
||||
except Exception:
|
||||
pass
|
||||
print()
|
||||
|
||||
# Main menu
|
||||
|
||||
Reference in New Issue
Block a user