|
18 | 18 | unchanged and never exchanged. Every other (opaque) credential is treated as |
19 | 19 | an API token and exchanged; set ``HOTDATA_DISABLE_JWT_EXCHANGE`` to force a |
20 | 20 | raw, non-JWT credential through as-is (local/dev setups, rollback). |
21 | | -* **Opt-out** -- if ``HOTDATA_DISABLE_JWT_EXCHANGE`` is set to any truthy value, |
22 | | - the credential is always returned as-is (hard escape hatch for rollout). |
| 21 | +* **Opt-out** -- if ``HOTDATA_DISABLE_JWT_EXCHANGE`` is set to an affirmative |
| 22 | + value (``1``/``true``/``yes``/``on``), the credential is always returned |
| 23 | + as-is (hard escape hatch for rollout); ``0``/``false``/empty do not opt out. |
23 | 24 | * **In-memory cache only** -- no disk writes. The server already de-duplicates |
24 | 25 | mints (keyed by ``sha256(api_token)``), so per-process caching is sufficient. |
25 | 26 | * **Thread-safe** -- a :class:`threading.Lock` with single-flight mint covers |
|
46 | 47 | _TIMEOUT = 30.0 # seconds -- never let a stalled token endpoint hang every request |
47 | 48 | _CLIENT_ID = "hotdata-python-sdk" |
48 | 49 |
|
49 | | -# Env var that disables exchange entirely (any truthy value). Used as a hard |
50 | | -# escape hatch during the rollout window and for local/dev setups. |
| 50 | +# Env var that disables exchange entirely. Used as a hard escape hatch during |
| 51 | +# the rollout window and for local/dev setups. Only affirmative values opt out |
| 52 | +# (see _DISABLE_VALUES) so that ``=0`` / ``=false`` do NOT silently disable it. |
51 | 53 | _DISABLE_ENV = "HOTDATA_DISABLE_JWT_EXCHANGE" |
| 54 | +_DISABLE_VALUES = {"1", "true", "yes", "on"} |
52 | 55 |
|
53 | 56 | # The SOCKS schemes urllib3 routes through SOCKSProxyManager rather than the |
54 | 57 | # plain ProxyManager. Mirrors hotdata/rest.py's SUPPORTED_SOCKS_PROXIES. |
@@ -104,6 +107,8 @@ def _pool_from_config(configuration): |
104 | 107 | pool_args["assert_hostname"] = configuration.assert_hostname |
105 | 108 | if configuration.tls_server_name: |
106 | 109 | pool_args["server_hostname"] = configuration.tls_server_name |
| 110 | + if configuration.socket_options is not None: |
| 111 | + pool_args["socket_options"] = configuration.socket_options |
107 | 112 | # `retries`/`maxsize` are intentionally not mirrored: the exchange is a |
108 | 113 | # single bounded-timeout request that fails fast rather than retrying. |
109 | 114 |
|
@@ -140,9 +145,10 @@ def __init__(self, credential, configuration, pool=None): |
140 | 145 |
|
141 | 146 | @property |
142 | 147 | def _needs_exchange(self): |
143 | | - # Opt-out wins outright: any truthy HOTDATA_DISABLE_JWT_EXCHANGE means |
144 | | - # send the credential as-is, never touching the token endpoint. |
145 | | - if os.environ.get(_DISABLE_ENV): |
| 148 | + # Opt-out wins outright: an affirmative HOTDATA_DISABLE_JWT_EXCHANGE |
| 149 | + # (1/true/yes/on) means send the credential as-is, never touching the |
| 150 | + # token endpoint. Other values (incl. 0/false/empty) do not opt out. |
| 151 | + if os.environ.get(_DISABLE_ENV, "").strip().lower() in _DISABLE_VALUES: |
146 | 152 | return False |
147 | 153 | # A compact JWT always starts with "eyJ" (base64 of '{"'), matching the |
148 | 154 | # Gateway's own ``^Bearer eyJ.*`` detection -- those already are what we |
|
0 commit comments