Metadata-Version: 2.4
Name: vibedata-studio-azure-cred-broker
Version: 0.1.0
Summary: Azure TokenCredential that exchanges a VibeData Studio intent access token (vd_iat_*) at the Studio credential broker for downstream, audience-bound Azure tokens (Fabric SQL/API, OneLake storage, Key Vault, ARM). Works with dbt-fabricspark token_credential auth, dlt destinations, and Key Vault SecretClient.
Author-email: Vibedata <eng@acceleratedata.ai>
License: MIT
Keywords: azure,credentials,dbt,dlt,fabric,studio,vibedata
Requires-Python: >=3.11
Requires-Dist: azure-core>=1.30.0
Requires-Dist: requests>=2.31.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: responses>=0.25; extra == 'dev'
Description-Content-Type: text/markdown

# vibedata-studio-azure-cred-broker

An Azure [`TokenCredential`](https://learn.microsoft.com/python/api/azure-core/azure.core.credentials.tokencredential)
that mints downstream Azure / Microsoft Fabric tokens through the **VibeData Studio
credential broker**.

Inside a Studio agent container the backend writes an intent-scoped bearer
(`vd_iat_*`) to a tmpfs file. `StudioAzureCredBroker` reads that bearer and
exchanges it at the broker's `POST /token` endpoint for a short-lived,
**audience-bound** Azure access token (Fabric SQL, OneLake storage, Key Vault,
Fabric API, ARM). The downstream credential is only ever minted by Studio.

Works with anything that speaks the `azure-core` `TokenCredential` protocol:

- **dbt-fabricspark** (`authentication: token_credential`)
- **dlt** destinations (OneLake / ADLS)
- **Key Vault** `SecretClient`

## How it resolves the broker

Pointers come from the environment, both overridable via constructor kwargs:

| Env var             | Kwarg             | Meaning                                              |
| ------------------- | ----------------- | ---------------------------------------------------- |
| `VD_AZ_TOKEN_URL`   | `broker_url`      | Broker base URL (e.g. `http://host.docker.internal:<port>/api/v1/credential-broker`) |
| `VD_CREDENTIAL_FILE`| `credential_file` | tmpfs path holding the `vd_iat_*` bearer (`/run/vd/credential`) |

The bearer is re-read on **every** `get_token` call (the backend rotates it).
Both pointers are required — the credential raises if either is missing.

## Scope → audience map

`get_token(scope)` maps the requested Azure scope to a broker audience:

| Azure scope                                          | Audience      |
| ---------------------------------------------------- | ------------- |
| `https://database.windows.net/.default`              | `sql`         |
| `https://storage.azure.com/.default`                 | `storage`     |
| `https://vault.azure.net/.default`                   | `vault`       |
| `https://api.fabric.microsoft.com/.default`          | `fabric_api`  |
| `https://analysis.windows.net/powerbi/api/.default`  | `fabric_cli`  |
| `https://management.azure.com/.default`              | `arm`         |

An unmapped scope raises `ScopeNotAllowedError`. Override or extend via the
`audience_map` kwarg.

## dbt usage (`profiles.yml`)

```yaml
my_project:
  outputs:
    ephemeral_dev:
      type: fabricspark
      method: livy
      authentication: token_credential
      credential_class: "vibedata_studio_azure_cred_broker.StudioAzureCredBroker"
      # No credential_kwargs needed — VD_AZ_TOKEN_URL and VD_CREDENTIAL_FILE
      # are read from the environment injected by Studio.
      endpoint: https://api.fabric.microsoft.com/v1
      workspaceid: "{{ env_var('EPHEMERAL_WORKSPACE_ID') }}"
      lakehouseid: "{{ env_var('EPHEMERAL_LAKEHOUSE_ID') }}"
      lakehouse:   "{{ env_var('EPHEMERAL_LAKEHOUSE_NAME') }}"
      schema:      "{{ env_var('EPHEMERAL_SCHEMA') }}"
  target: ephemeral_dev
```

## dlt / Key Vault usage

```python
from azure.keyvault.secrets import SecretClient
from vibedata_studio_azure_cred_broker import StudioAzureCredBroker

client = SecretClient(vault_url=vault_url, credential=StudioAzureCredBroker())
```
