Skip to content

fix(config): parse NBI_ENABLED_PROVIDERS with split_csv (#435) - #436

Open
pjdoland wants to merge 1 commit into
plmbr:mainfrom
pjdoland:fix/435-enabled-providers-whitespace
Open

pjdoland wants to merge 1 commit into
plmbr:mainfrom
pjdoland:fix/435-enabled-providers-whitespace

Conversation

@pjdoland

Copy link
Copy Markdown
Collaborator

Summary

NBI_ENABLED_PROVIDERS="github-copilot, ollama" re-enabled only github-copilot. The value was split on , with no strip, so any entry with surrounding whitespace never matched. Measured against the old function:

NBI_ENABLED_PROVIDERS github-copilot ollama
github-copilot,ollama True True
github-copilot, ollama True False
ollama False False
ollama, False True

It fails closed, which is the safer direction, but silently: the admin sees the provider still missing from the picker, with no error anywhere and no way to tell why short of reading the source.

Solution

split_csv already lives 30 lines above in the same module, and its docstring names this very variable as a caller of the "comma-separated, whitespace-tolerant, empty-dropping" format. It simply was not used here, which is also why the sibling flag is_builtin_tool_enabled_in_env handles the same input shape correctly while this one did not.

Dropping empty tokens closes a second, older fail-open along the way: ''.split(',') is [''], so is_provider_enabled_in_env('') returned True for an unset variable. Unreachable today because no registered provider has an empty id, but it is the wrong default for a re-enable check.

Only surrounding whitespace is treated as noise. Matching stays case sensitive, and an id with an inner space still only matches itself: provider ids are exact strings everywhere else (llm_providers keys), so loosening either would make the denylist and the re-enable list disagree about what a provider is called. Both are pinned by tests so a future "be more forgiving" change has to be deliberate.

Testing

pytest 1773 passed, including 20 new cases in tests/test_enabled_providers_env.py. Nothing covered this function or the variable before.

Covered: comma-separated, comma-space (the reported regression), surrounding whitespace in five forms including tab and newline, repeated and trailing commas, a provider not in the list, unset, blank values, the empty-provider-id fail-open, case sensitivity, and internal whitespace.

Verified by mutation that these pin the regression rather than the implementation. Reverting to the unstripped split fails 8 of the 20; the 12 that keep passing are exactly the cases that never depended on stripping.

tsc --noEmit clean, jest 423 passed, eslint, stylelint, prettier clean. No TypeScript changed.

Risks and follow-ups

  • The consumer is untested. The only caller is the is_provider_enabled closure in the capabilities handler (extension.py:663), reached when allow_enabling_providers_with_env is on. That handler has no test harness in this repo, so "the closure consults this function correctly" remains uncovered, as it was before.
  • No behavior changes for an admin who was already writing the value without spaces, which is the form the docs show.
  • Review coverage was curtailed: the persona review I would normally run was cut short by a session rate limit, so this had my own diff pass plus the automated gate and the mutation check rather than independent reviewer eyes.

Closes #435

`is_provider_enabled_in_env` split the variable on `,` with no strip, so
`NBI_ENABLED_PROVIDERS="github-copilot, ollama"` re-enabled only
`github-copilot`. The comma-space form is the natural way to write a
list, and a single stray space around a lone entry disabled it outright.
It fails closed, so the admin sees the provider still missing with no
error anywhere and no way to tell why short of reading the source.

`split_csv` lives 30 lines above in the same module and its docstring
already names this variable as a caller of the
comma-separated-whitespace-tolerant format. It was simply never used
here, which is also why the sibling flag `is_builtin_tool_enabled_in_env`
behaves correctly for the same input shape.

Dropping empty tokens closes a second, older fail-open along the way:
`''.split(',')` is `['']`, so an empty provider id matched an unset
variable and read as enabled. Unreachable today because no registered
provider has an empty id, but it is the wrong default for a re-enable
check.

Only surrounding whitespace is treated as noise. Matching stays case
sensitive and an id with an inner space still only matches itself, since
provider ids are exact strings everywhere else and loosening either
would make the denylist and the re-enable list disagree about what a
provider is called.

Nothing covered this function or the variable before. Verified by
mutation that the new tests pin the regression: reverting to the
unstripped split fails 8 of the 20, and the 12 that keep passing are the
cases that never depended on stripping.
@pjdoland pjdoland added the bug Something isn't working label Sep 14, 2026
@pjdoland
pjdoland requested a review from mbektas September 14, 2026 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(config): NBI_ENABLED_PROVIDERS silently ignores entries with surrounding whitespace

1 participant