Repository navigation
FEAT: Add a "no key" auth mode for OpenAI-compatible targets - #3809
Open
varunj-msft wants to merge 3 commits into
Open
varunj-msft wants to merge 3 commits into
varunj-msft wants to merge 3 commits into
Conversation
OpenAI-compatible servers such as Ollama and vLLM need no key, but a target could only be created with one: an empty key fell back to the server's key variable or failed with "No API key available", so users typed a dummy key. Add auth_mode "none" for the OpenAI targets. It reads no key, mints no Entra token and skips OPENAI_ADDITIONAL_REQUEST_HEADERS, and passes the SDK the same non-secret "not-needed" placeholder the startup initializer already uses. Copies of a no-key target stay no-key. The create API and the target dialog offer it only for target types that list it; Azure ML, Prompt Shield and Blob Storage reject it.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This is the "No key" option from the work on saving Registry entries across restarts. It doesn't depend on the rest of that work.
Problem. An OpenAI-compatible server that needs no key, such as Ollama, vLLM or LM Studio, can't be added without one. Leaving the key empty uses the server's
OPENAI_CHAT_KEYandOPENAI_ADDITIONAL_REQUEST_HEADERSand sends them to that endpoint, or fails with "No API key available" when the variable isn't set. The workaround is typing a dummy key.Change. A new
auth_mode="none", offered by the OpenAI targets:OPENAI_ADDITIONAL_REQUEST_HEADERS. The OpenAI SDK requires a key, so the target passes itnot-needed, the placeholder the startup initializer already uses for keyless endpoints; servers that need no key ignore it. An explicitapi_keywith"none"raises in Python, and the API drops it, as it does for identity.api_keyorheadersto null. A copy that passes a key, even an empty one, is rejected unless it also setsauth_modetoapi_key./api/targets/typeslistsnonefor the OpenAI targets, and the create dialog shows a "No key" option for target types that list it (and for the OpenAI targets when the type list can't load), without the key field.AuthMode, so they now reject a mode they don't list (a smallPromptTarget._validate_auth_mode) instead of treating"none"as a key.TargetIdentifieruse the sharedAuthModeinstead of their own two-value copies.Why a placeholder rather than dropping the header: the SDK rejects a request without a credential unless that request omits the header itself, and some calls can't (video polling takes no per-request headers), so dropping it would mean changing every call site for a header these servers ignore.
What stays the same. The default (
api_key), identity, the deprecated Entra ID fallback, the empty-key behavior ofapi_keymode, and existing targets and their identifier hashes. The OpenAI SDK still reads its ownOPENAI_ORG_ID,OPENAI_PROJECT_IDandOPENAI_CUSTOM_HEADERSin every mode.#3600 and #3777 change lines next to this PR's in
pyrit/backend/models/targets.pyandtests/unit/registry/test_target_registry.py, so whichever merges second needs a small merge.Tests and Documentation
nonefor types that don't list it; copies stay keyless, including withapi_keyorheadersset to null orheadersset to an empty string; Azure ML, Prompt Shield and Blob rejectnone;/typeslists it for the OpenAI targets only; the dialog offers and submits "No key", doesn't offer it for Azure ML, falls back to API key when switching to such a type, and offers it for the OpenAI targets when the type list can't load.pytest -n 4 tests/unit/auth tests/unit/embedding tests/unit/models/identifiers tests/unit/models/test_import_boundary.py tests/unit/registry/test_target_registry.py tests/unit/backend/test_target_service.py tests/unit/backend/test_temporary_components.py tests/unit/backend/test_api_routes.py::TestTargetRoutes tests/unit/prompt_target/target/test_openai_target_auth.py tests/unit/prompt_target/target/test_openai_chat_target.py tests/unit/prompt_target/target/test_realtime_target.py tests/unit/prompt_target/target/test_prompt_target.py tests/unit/prompt_target/target/test_azure_ml_chat_target.py tests/unit/prompt_target/target/test_prompt_shield_target.py tests/unit/prompt_target/target/test_prompt_target_azure_blob_storage.py: 1193 passed.npx jest src/components/Config/CreateTargetDialog.test.tsx: 75 passed.npx eslint --max-warnings 0on the changed frontend files: clean.uv run --frozen --extra all --link-mode=copy ty check pyrit: all checks passed.pre-commit: passed.OPENAI_CHAT_KEYandOPENAI_ADDITIONAL_REQUEST_HEADERSset to test values, creating anOpenAIChatTargetfor a local OpenAI-compatible test server and sending a chat message through the attacks API: on main,auth_mode: "none"is a 422, and an empty-key target sends the server's key and extra header to that server. On this branch,auth_mode: "none"is a 201, the message gets the server's reply, and the server receivesAuthorization: Bearer not-neededand no server header.AzureMLChatTargetwithnoneis a 400.doc/code/setup/1_configuration.pyand its notebook get a paragraph and example forauth_mode="none"(Markdown only, both files edited); the backend README's trust-boundary list mentions the opt-out.