|
| 1 | +""" |
| 2 | +Client attribution via the shared ``X-Wherobots-Client`` header. |
| 3 | +
|
| 4 | +``X-Wherobots-Client`` is an ordered, append-only, comma-separated list of |
| 5 | +hops modelled on ``X-Forwarded-For``: the leftmost hop is the ORIGIN client |
| 6 | +and every component appends its own hop on the right. It lets Wherobots |
| 7 | +services attribute a request to the client it came from. |
| 8 | +
|
| 9 | +This provider is an origin client: an Airflow DAG is where the request enters |
| 10 | +the Wherobots client ecosystem, so it emits ``client=airflow;ver=<version>`` |
| 11 | +as the leftmost hop. Where the provider goes through another Wherobots client |
| 12 | +(the Python DB-API driver, for the SQL hook), that client appends its own hop |
| 13 | +to the right, producing e.g. |
| 14 | +``client=airflow;ver=1.7.0, client=dbapi;ver=0.28.1``. |
| 15 | +
|
| 16 | +The header is advisory: it is client-asserted and informational only, and must |
| 17 | +never influence authentication or authorization. |
| 18 | +""" |
| 19 | + |
| 20 | +from importlib import metadata |
| 21 | +from typing import Dict, Final |
| 22 | + |
| 23 | +from airflow_providers_wherobots.hooks.base import PACKAGE_NAME |
| 24 | + |
| 25 | +# Canonical name of the shared, cross-service client-chain header. |
| 26 | +WHEROBOTS_CLIENT_HEADER: Final[str] = "X-Wherobots-Client" |
| 27 | + |
| 28 | +# Canonical, stable vocabulary token for this client. Renaming it splits its |
| 29 | +# history in the platform's attribution analytics, so it must not change. |
| 30 | +CLIENT_TOKEN: Final[str] = "airflow" |
| 31 | + |
| 32 | +# Sentinel used when the installed distribution's version can't be resolved |
| 33 | +# (e.g. the provider is imported from a source tree that was never installed). |
| 34 | +UNKNOWN_VERSION: Final[str] = "unknown" |
| 35 | + |
| 36 | +# Commas separate hops and semicolons separate a hop's fields, so neither may |
| 37 | +# appear inside a value. |
| 38 | +_DELIMITERS = str.maketrans({",": "_", ";": "_"}) |
| 39 | + |
| 40 | + |
| 41 | +def _resolve_provider_version() -> str: |
| 42 | + """Return the installed provider version, or ``unknown`` if unavailable.""" |
| 43 | + try: |
| 44 | + return metadata.version(PACKAGE_NAME) |
| 45 | + except metadata.PackageNotFoundError: |
| 46 | + return UNKNOWN_VERSION |
| 47 | + |
| 48 | + |
| 49 | +# Resolved once at import: `importlib.metadata.version` scans the installed |
| 50 | +# package database on each call, and the version can't change within a process. |
| 51 | +PROVIDER_VERSION: Final[str] = _resolve_provider_version() |
| 52 | + |
| 53 | +# This provider's single hop, e.g. `client=airflow;ver=1.7.0`. |
| 54 | +CLIENT_HOP: Final[str] = ( |
| 55 | + f"client={CLIENT_TOKEN};ver={PROVIDER_VERSION.translate(_DELIMITERS)}" |
| 56 | +) |
| 57 | + |
| 58 | + |
| 59 | +def client_attribution_header() -> Dict[str, str]: |
| 60 | + """Return the ``X-Wherobots-Client`` header carrying this provider's hop.""" |
| 61 | + return {WHEROBOTS_CLIENT_HEADER: CLIENT_HOP} |
0 commit comments