fix: OpenAI image plugin 403 on project-scoped keys - #60749
Conversation
…500 on password-only providers
Two fixes:
1. OpenAI image generation plugin (`plugins/image_gen/openai`):
The OpenAI SDK auto-injects the `OpenAI-Project` header from the API
key's associated project. For the image generation endpoint, this
triggers a project-level model access check that fails with 403 for
project-scoped keys that have a restricted model allow-list — even
when the model is explicitly in the project's allowed list.
Fix: pass `default_headers={"OpenAI-Project": ""}` to bypass the
project-level check and fall back to org-level access.
2. Dashboard auth routes (`hermes_cli/dashboard_auth/routes.py`):
The `/auth/login?provider=basic` endpoint called `start_login()` on
password-only providers, which raises `NotImplementedError` (500).
Fix: check `supports_password` before calling `start_login()` and
redirect to `/login` (which renders the password form) instead.
Closes NousResearch#60748
teknium1
left a comment
There was a problem hiding this comment.
Thanks for investigating both setup paths. The dashboard portion has since landed independently, while the image change needs revalidation against the pinned SDK.
Problems
hermes_cli/dashboard_auth/routes.py:195-202on current main (commit3e24b16f5) already redirects password providers, validates and encodesnext, and preserves the proxy prefix. The PR's changed redirect uses a static/loginand interpolates rawnext, so that hunk should not be salvaged.- The pinned OpenAI 2.24.0 SDK obtains
projectonly from the argument orOPENAI_PROJECT_ID(.venv/lib/python3.11/site-packages/openai/_client.py:153-155), not from API-key association. Its header assembly overlays custom headers afterOpenAI-Project(:340-346), so the proposed value sends an explicit empty header.tests/plugins/image_gen/test_openai_provider.py:201-280does not cover client/header construction, and the PR adds no regression test.
Suggested changes
- Keep the current-main dashboard implementation and its E2E redirect coverage at
tests/hermes_cli/test_dashboard_auth_password_login.py:211-217. - Reproduce the image case with
OPENAI_PROJECT_IDand add a focused header-construction regression test before choosing a supported fix.
Automated hermes-sweeper review.
|
|
||
| # Password-only providers don't have an OAuth redirect flow — redirect | ||
| # to the login page which renders the username/password form. | ||
| if getattr(p, "supports_password", False): |
There was a problem hiding this comment.
Current main already has this redirect in 3e24b16f5, but it uses f"{_prefix(request)}/login" and validates/encodes next (routes.py:195-202). A static path here would break prefixed deployments, and raw next would discard the current open-redirect defense.
| modality = "image" if is_edit else "text" | ||
|
|
||
| client = openai.OpenAI() | ||
| client = openai.OpenAI(default_headers={"OpenAI-Project": ""}) |
There was a problem hiding this comment.
The pinned OpenAI 2.24.0 client derives project only from OPENAI_PROJECT_ID, not from the API key (openai/_client.py:153-155), and custom default headers override its project header (:340-346). This sends a literal empty header rather than demonstrating omission; please establish the supported repro and add a constructor/header regression test before changing the client.
|
Thanks — agreed on both points. I'll rebase onto current main and drop the dashboard-auth hunk entirely; For the image issue, my original explanation was too strong: OpenAI 2.24.0 does not derive Plan: narrow the PR to the image issue, run a 2×2 matrix (project-scoped key × { |
|
Edited PR title and body to reflect the narrowed scope (dashboard-auth portion dropped — covered by |
Summary
Narrowed to the OpenAI image plugin issue following review feedback. The dashboard-auth hunk from the original submission has been dropped — current main (
3e24b16f5) already ships the more complete implementation (proxy prefix,nextvalidation/encoding, open-redirect defense).Problem
Project-scoped OpenAI API keys (
sk-proj-…) fail with 403 on image-generation calls. The pinned OpenAI 2.24.0 client derivesprojectonly from the constructor argument orOPENAI_PROJECT_ID(openai/_client.py:153-155), not from the API key itself. An earlier hypothesis — thatdefault_headers={"OpenAI-Project": ""}makes the SDK inject the project from key association — does not hold; the SDK overlays custom headers after its ownOpenAI-Project(:340-347), so this sends a literal empty header.Next steps (per review)
main; drop the dashboard-auth hunk entirely.OPENAI_PROJECT_IDset / unset} × {default client / explicit empty header}.tests/plugins/image_gen/test_openai_provider.py.Edit note
PR title and body edited to reflect the narrowed scope; the dashboard-auth portion was dropped because it is covered by
3e24b16f5.