Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

fix(config): provider probes ignore configured extra headers

Open
#823 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
75/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
api, backend, testing

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_provider resolves an endpoint through provider_endpoints, but reads only its key and base URL. The generic request constructs a new Authorization header without using endpoint.extra_headers.
  • raven/providers/factory.py forwards eps[0].extra_headers (or each rotated endpoint's headers) to LiteLLMProvider.
  • raven/providers/litellm_provider.py forwards those headers to the completion call.
  • raven/cli/provider_commands.py:provider_test_cmd and raven/rpc/methods/model.py:model_fetch_models call 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from EverMind-AI/Raven

All issues in EverMind-AI/Raven

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.