|
7 | 7 |
|
8 | 8 | They verify the pinned public contract: |
9 | 9 |
|
10 | | -* first mint -- an ``hd_`` credential POSTs an ``api_token`` grant to |
11 | | - ``/v1/auth/jwt`` (form-encoded, correct Content-Type and |
| 10 | +* first mint -- an opaque (non-JWT) credential POSTs an ``api_token`` grant |
| 11 | + to ``/v1/auth/jwt`` (form-encoded, correct Content-Type and |
12 | 12 | ``client_id``) and returns the minted ``access_token``; |
13 | 13 | * cache hit -- a second ``bearer_value()`` within TTL does not re-hit the |
14 | 14 | pool; |
@@ -400,35 +400,45 @@ def test_deepcopied_manager_credential_still_mints() -> None: |
400 | 400 |
|
401 | 401 |
|
402 | 402 | # -------------------------------------------------------------------------- |
403 | | -# Non-hd_ credentials pass through (only real API tokens are exchanged) |
| 403 | +# Opaque (non-JWT) credentials are exchanged -- the prefix is not gated |
404 | 404 | # -------------------------------------------------------------------------- |
405 | 405 |
|
406 | 406 |
|
407 | | -def test_non_hd_credential_is_passed_through_unchanged() -> None: |
408 | | - """Only ``hd_`` API tokens are exchanged. A non-``hd_`` value (e.g. a |
409 | | - local/dev/test credential) must be sent as-is and never hit the token |
410 | | - endpoint -- otherwise local setups and the rollout window break.""" |
411 | | - pool = _FakePool([_mint_response()]) |
412 | | - mgr = _TokenManager("test-key", _config(), pool=pool) |
| 407 | +def test_bare_hex_token_is_exchanged() -> None: |
| 408 | + """Hotdata API tokens are bare hex with no ``hd_`` prefix (the prefix in |
| 409 | + the docs is cosmetic and not enforced by the server). Any opaque, non-JWT |
| 410 | + credential must therefore be exchanged, not passed through.""" |
| 411 | + raw = "8a4bfd9cfa6926344f770d6b9a093c2b559dafc4de2a69137acb93e7e9821c7b" |
| 412 | + pool = _FakePool([_mint_response(access_token="eyJ.minted.jwt")]) |
| 413 | + mgr = _TokenManager(raw, _config(), pool=pool) |
413 | 414 |
|
414 | | - assert mgr.bearer_value() == "test-key" |
415 | | - assert pool.calls == [] |
| 415 | + assert mgr.bearer_value() == "eyJ.minted.jwt" |
| 416 | + assert len(pool.calls) == 1 |
| 417 | + assert _form(pool.calls[0]["body"])["api_token"] == [raw] |
416 | 418 |
|
417 | 419 |
|
418 | | -def test_configuration_with_non_hd_key_never_mints() -> None: |
419 | | - """End-to-end regression for the predicate: building a Configuration with a |
420 | | - non-``hd_`` key (as the arrow tests do) must not trigger a network mint when |
421 | | - ``auth_settings()`` reads ``api_key``.""" |
422 | | - cfg = Configuration(host="https://api.hotdata.test", api_key="test-key") |
423 | | - # Wire a recording pool in; if exchange were (wrongly) attempted it would |
424 | | - # show up here instead of trying a real socket. |
425 | | - pool = _FakePool([_mint_response()]) |
| 420 | +def test_configuration_exchanges_bare_token_then_opt_out_passes_through( |
| 421 | + monkeypatch: pytest.MonkeyPatch, |
| 422 | +) -> None: |
| 423 | + """End-to-end at the Configuration level: a bare token is exchanged so |
| 424 | + ``auth_settings()`` carries the minted JWT; with the opt-out env var set the |
| 425 | + raw token is sent unchanged (the arrow-test style dummy-key setup).""" |
| 426 | + raw = "8a4bfd9c0bare0token" |
| 427 | + |
| 428 | + # Exchange path: auth_settings() carries the minted JWT, not the raw token. |
| 429 | + pool = _FakePool([_mint_response(access_token="eyJ.live.jwt")]) |
| 430 | + cfg = Configuration(host="https://api.hotdata.test", api_key=raw) |
426 | 431 | cfg._token_manager._pool = pool |
| 432 | + assert _bearer_from(cfg.auth_settings()) == "Bearer eyJ.live.jwt" |
| 433 | + assert len(pool.calls) == 1 |
427 | 434 |
|
428 | | - assert cfg.api_key == "test-key" |
429 | | - bearer = _bearer_from(cfg.auth_settings()) |
430 | | - assert bearer == "Bearer test-key" |
431 | | - assert pool.calls == [] |
| 435 | + # Opt-out path: same raw token, exchange disabled -> sent as-is, no mint. |
| 436 | + monkeypatch.setenv("HOTDATA_DISABLE_JWT_EXCHANGE", "1") |
| 437 | + pool2 = _FakePool([_mint_response()]) |
| 438 | + cfg2 = Configuration(host="https://api.hotdata.test", api_key=raw) |
| 439 | + cfg2._token_manager._pool = pool2 |
| 440 | + assert _bearer_from(cfg2.auth_settings()) == f"Bearer {raw}" |
| 441 | + assert pool2.calls == [] |
432 | 442 |
|
433 | 443 |
|
434 | 444 | # -------------------------------------------------------------------------- |
|
0 commit comments