fix(config): provider probes ignore configured extra headers
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 75/100
Research direction
Start with test_provider in raven/config/update_providers.py and compare how it resolves endpoint credentials and headers with raven/providers/factory.py. Run the supplied httpx.MockTransport reproduction to confirm the three header configurations fail, then add regression coverage for flat, endpoint-specific, inherited, and absent headers. Done means probes forward effective headers without weakening credential verification.
Written by the indexing model from the issue text.
Description
Summary
Provider credential probes discard configured extra_headers. A relay requiring an additional header such as X-Tenant can reject the probe with HTTP 401, which Raven reports as invalid_key, even though the configured header is present and resolved correctly.
This affects section-level headers, endpoint-specific headers, and headers inherited by an endpoint from its provider section. It is separate from Gemini official-endpoint authentication selection in #820.
The CLI's raven provider test and the RPC model catalogue fetch call this probe. The CLI maps this failure to advice to replace the API key. The runtime factory, in contrast, forwards resolved endpoint headers to its provider; this report does not claim a live chat or browser E2E test.
Steps to reproduce
From a source checkout with dependencies installed, save the following as /tmp/repro_provider_headers.py and run:
PYTHONPATH=. uv run --no-sync python /tmp/repro_provider_headers.py
It uses a temporary config, dummy credentials, and httpx.MockTransport; it makes no network requests and does not read or modify the user's configuration. The mock relay requires a tenant header. The control request sends the same URL and key plus the configured header.
"""Reproduce provider probes dropping configured headers without network access."""
import json
import tempfile
from pathlib import Path
import httpx
from raven.config.schema import ProviderConfig
from raven.config.update_providers import test_provider
from raven.providers.endpoints import provider_endpoints
base = "https://relay.example.test/v1"
cases = {
"flat": {
"apiKey": "dummy-key", "apiBase": base,
"extraHeaders": {"X-Tenant": "test-tenant"},
},
"endpoint": {"endpoints": [{
"label": "primary", "apiKey": "dummy-key", "apiBase": base,
"extraHeaders": {"X-Tenant": "test-tenant"},
}]},
"inherited": {
"apiBase": base, "extraHeaders": {"X-Tenant": "test-tenant"},
"endpoints": [{"label": "primary", "apiKey": "dummy-key"}],
},
}
with tempfile.TemporaryDirectory() as directory:
config = Path(directory) / "config.json"
for name, section in cases.items():
config.write_text(json.dumps({"providers": {"custom": section}}))
seen = []
def relay(request):
seen.append(request.headers.get("X-Tenant"))
if request.headers.get("X-Tenant") != "test-tenant":
return httpx.Response(401, json={"error": "missing tenant header"})
return httpx.Response(200, json={"data": [{"id": "test-model"}]})
transport = httpx.MockTransport(relay)
probe = test_provider("custom", config_path=config, transport=transport)
endpoint = provider_endpoints(ProviderConfig.model_validate(section))[0]
with httpx.Client(transport=transport) as client:
control = client.get(
base + "/models",
headers={"Authorization": "Bearer dummy-key", **endpoint.extra_headers},
)
print(f"{name}: probe={probe['http_status']}/{probe['status']}, "
f"sent_tenant={seen[0]!r}, control={control.status_code}")
assert probe["status"] == "invalid_key"
assert seen[0] is None
assert control.status_code == 200
Expected behavior
The probe forwards the selected endpoint's effective custom headers, including inherited headers. All three configured cases reach the mock relay with X-Tenant: test-tenant and receive HTTP 200.
Actual behavior
All three probes omit X-Tenant and return invalid_key / HTTP 401. Each control request with the resolved headers receives HTTP 200.
Code evidence:
raven/config/update_providers.py:test_providerresolves an endpoint throughprovider_endpoints, but reads only its key and base URL. The generic request constructs a new Authorization header without usingendpoint.extra_headers.raven/providers/factory.pyforwardseps[0].extra_headers(or each rotated endpoint's headers) toLiteLLMProvider.raven/providers/litellm_provider.pyforwards those headers to the completion call.raven/cli/provider_commands.py:provider_test_cmdandraven/rpc/methods/model.py:model_fetch_modelscall the affected probe.
Suggested regression coverage: flat headers, endpoint headers, inherited headers, and unchanged requests when custom headers are absent. Header merge precedence and the optional credential-control request should be checked together so forwarding headers does not weaken verification.
Environment
- Raven: 0.2.3, source checkout at e6c0344cb7ce00db25d554e4bb671ec1909a8f9f
- OS: Darwin 25.5.0, arm64
- Python: 3.12.14
- Shell: zsh
- Installation: project-local uv environment
- Node: not used in this backend-only reproduction
Logs or screenshots
flat: probe=401/invalid_key, sent_tenant=None, control=200
endpoint: probe=401/invalid_key, sent_tenant=None, control=200
inherited: probe=401/invalid_key, sent_tenant=None, control=200
- Dominant language
- Python
- Stars
- 4.1k
- Forks
- 94
- Avg merge
- 10h 2m
- Merged PRs (30d)
- 376
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from EverMind-AI/Raven
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
EverMind-AI/Raven#798 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
EverMind-AI/Raven#797 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
EverMind-AI/Raven#640 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
EverMind-AI/Raven#479 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 75/100
EverMind-AI/Raven#474 · 2 comments ·
Maintainers usually reply within 1 day
All issues in EverMind-AI/Raven
Similar issues
-
namespace operations
Difficulty 1/5 Under an hour Newbie friendliness 82/100
EclipseFdn/open-vsx.org#13573 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
collective/icalendar#1854 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
rancher/rancher-ai-agent#412 ·
Maintainers usually reply within 6 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
TUDelftGeodesy/DePSI#134 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
HenriquesLab/rxiv-maker#335 ·