fix: send Scheduler API Bearer auth from the task registrar
The Scheduler's task-management endpoints (GET/POST /tasks, PUT
/tasks/{name}) are guarded by verify_api_key, but execute() built a bare
httpx.Client with no Authorization header: the existence probe 401'd
(misread as 'task absent') and every POST/PUT registration failed, so
--execute was never runnable end-to-end against the real Scheduler.
--execute now requires SCHEDULER_API_KEY from the environment (never
stored) and sends Authorization: Bearer on all registrar HTTP calls.
Deploy notes updated alongside the LIBRARY_API_KEY requirement.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbFZyDvYksazX6nYQYZ67L
This commit is contained in:
@@ -128,3 +128,54 @@ class TestSchedulerTaskDefinitions:
|
||||
assert "DRY RUN" in out
|
||||
assert "library_integrity_check" in out
|
||||
assert mod.API_KEY_PLACEHOLDER in out # placeholder, never a real key
|
||||
|
||||
def test_execute_requires_scheduler_api_key(self, capsys, monkeypatch):
|
||||
"""--execute must refuse to run without SCHEDULER_API_KEY (the
|
||||
Scheduler's task endpoints are Bearer-guarded; without the key
|
||||
every probe 401s and registration silently fails)."""
|
||||
mod = self._load_module()
|
||||
monkeypatch.setattr(
|
||||
"sys.argv", ["register_scheduler_tasks.py", "--execute"]
|
||||
)
|
||||
monkeypatch.setenv("SCHEDULER_URL", "http://scheduler.test:8090")
|
||||
monkeypatch.delenv("SCHEDULER_API_KEY", raising=False)
|
||||
|
||||
def _boom(*args, **kwargs):
|
||||
raise AssertionError("must not contact the Scheduler without a key")
|
||||
|
||||
monkeypatch.setattr(mod.httpx, "Client", _boom)
|
||||
|
||||
assert mod.main() == 1
|
||||
assert "SCHEDULER_API_KEY" in capsys.readouterr().out
|
||||
|
||||
def test_execute_sends_scheduler_bearer_auth(self, monkeypatch):
|
||||
"""The registrar's own HTTP client must carry
|
||||
Authorization: Bearer $SCHEDULER_API_KEY on every call."""
|
||||
import httpx as real_httpx
|
||||
|
||||
mod = self._load_module()
|
||||
seen = {"auth_headers": [], "paths": []}
|
||||
|
||||
def handler(request: real_httpx.Request) -> real_httpx.Response:
|
||||
seen["auth_headers"].append(request.headers.get("Authorization"))
|
||||
path = request.url.path
|
||||
seen["paths"].append(f"{request.method} {path}")
|
||||
if path == "/health":
|
||||
return real_httpx.Response(200, json={"status": "healthy"})
|
||||
if request.method == "GET" and path.startswith("/tasks/"):
|
||||
return real_httpx.Response(404) # not registered yet
|
||||
return real_httpx.Response(200, json={"ok": True})
|
||||
|
||||
real_client = real_httpx.Client
|
||||
|
||||
def client_factory(**kwargs):
|
||||
kwargs["transport"] = real_httpx.MockTransport(handler)
|
||||
return real_client(**kwargs)
|
||||
|
||||
monkeypatch.setattr(mod.httpx, "Client", client_factory)
|
||||
|
||||
assert mod.execute("http://scheduler.test:8090", "sched-key-123") == 0
|
||||
assert seen["auth_headers"], "no HTTP calls were made"
|
||||
assert all(h == "Bearer sched-key-123" for h in seen["auth_headers"])
|
||||
# All three tasks created (404 probe -> POST /tasks)
|
||||
assert seen["paths"].count("POST /tasks") == len(mod.TASKS)
|
||||
|
||||
Reference in New Issue
Block a user