Skip to content

refactor: extract publishRoutingAllowlist and filter by model when publishing VK provider allowlist - #4221

Merged
akshaydeo merged 1 commit into
devfrom
06-09-fix_routing_governance_allowlsit_fixes
Jun 9, 2026
Merged

akshaydeo merged 1 commit into
devfrom
06-09-fix_routing_governance_allowlsit_fixes

Conversation

@Pratham-Mishra04

@Pratham-Mishra04 Pratham-Mishra04 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

The routing allowlist published to BifrostContextKeyRoutingAllowedProviders previously included all providers on a virtual key regardless of their allowed_models / blocked_models configuration. This meant a downstream routing layer (load balancing, model-catalog resolution) could select a provider that the VK explicitly forbids for the requested model. This PR fixes that by filtering the allowlist against the model being routed before publishing it.

Changes

  • Extracted the allowlist-publishing logic into a dedicated publishRoutingAllowlist method that filters each provider config against the resolved model using AllowedModels.IsAllowed / BlacklistedModels.IsBlocked before adding it to the allowed set.
  • Removed the previous inline allowlist construction in PreRequestHook, which unconditionally included every provider on the VK without any model-level filtering.
  • publishRoutingAllowlist is now called after routing rules have been applied (so the model is in its final post-routing state) for both the large-payload path (using ParseModelString on LargePayloadMetadata.Model) and the standard path (using req.GetRequestFields()).
  • An empty allowed slice continues to mean "no provider is permitted," preserving the existing fail-closed behaviour enforced by the empty-provider validation in handleRequest.
  • A nil virtual key is a no-op, so unauthenticated or VK-less requests are unaffected.

Type of change

  • Bug fix

Affected areas

  • Plugins

How to test

go test ./...
  1. Configure a virtual key with two providers where one provider has allowed_models that excludes the requested model.
  2. Send a request for that model and confirm the excluded provider is never selected by the load balancer or model-catalog resolver.
  3. Confirm that a request for a model permitted by both providers can still be routed to either.
  4. Confirm that a request where no provider permits the model fails closed rather than falling through to a forbidden provider.

Breaking changes

  • Yes
  • No

Related issues

Security considerations

This tightens provider selection enforcement on virtual keys. Previously, a model-level restriction on a VK provider config could be bypassed by a downstream routing layer picking that provider after governance failed to select one. That bypass path is now closed.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Summary by CodeRabbit

  • Bug Fixes
    • Improved consistency between routing rule application and provider allowlist enforcement for virtual keys with model restrictions, ensuring correct provider filtering is applied after routing decisions are made.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Pratham-Mishra04 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR moves when the governance plugin publishes the routing-allowed provider set from immediately after virtual-key selection to after routing decisions. A new publishRoutingAllowlist helper computes the allowlist for a specific model using the virtual key's allow/blacklist rules, and PreRequestHook calls it with the routed model in both large-payload and standard paths.

Changes

Model-aware provider allowlist publication

Layer / File(s) Summary
publishRoutingAllowlist helper
plugins/governance/main.go
New internal method computes and publishes the subset of a virtual key's providers that permit a given model, filtering by the VK's AllowedModels and BlacklistedModels rules, and stores the result in BifrostContextKeyRoutingAllowedProviders.
PreRequestHook refactoring
plugins/governance/main.go
Removes the prior allowlist publication immediately upon virtual-key selection; adds calls to publishRoutingAllowlist with the routed model in the large-payload branch (after parsing metadata model) and in the standard path (after applyRoutingRules), aligning the published allowlist with the post-routing model decision.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • maximhq/bifrost#4179: This PR introduces core allowlist enforcement that directly depends on BifrostContextKeyRoutingAllowedProviders, which the main PR now publishes post-routing.
  • maximhq/bifrost#3936: This PR enforces the routing allowlist and uses the context key that the main PR computes and filters by the bare model name.
  • maximhq/bifrost#3924: This PR modifies router and fallback parsing to filter providers based on the same context key that the main PR adjusts for post-routing timing.

Suggested reviewers

  • akshaydeo
  • danpiths

Poem

🐰 Hop! The allowlist now knows which way we're routed,
No more early guesses—we've finally computed it right,
Post-routing wisdom shines through the governance light.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main refactoring: extracting a new method and filtering the VK provider allowlist by model when publishing.
Description check ✅ Passed The PR description includes all major required sections: summary, changes, type of change, affected areas, how to test, breaking changes, security considerations, and a checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 06-09-fix_routing_governance_allowlsit_fixes

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 3/5

The routing allowlist filtering logic is an improvement over the old unconditional publish, but the model-allow check used in publishRoutingAllowlist is simpler than what loadBalanceProvider uses, and the two can disagree for real configurations.

The publishRoutingAllowlist check (IsAllowed) and the governance load-balancer check (IsModelAllowedForProvider) behave differently for provider-prefixed allowed_models entries: governance would permit the provider while the published allowlist would exclude it. In the large-payload path this contradiction is especially visible — runPreRequestRouting may select a provider via the catalog-aware path, then publishRoutingAllowlist immediately publishes an allowlist that omits that same provider. The ["*"] case runs the other direction (allowlist more permissive than governance), which can mislead downstream layers. Both gaps stem from the same root cause: the new method does not mirror the two-phase catalog check that loadBalanceProvider already uses.

plugins/governance/main.go — specifically the publishRoutingAllowlist method and its call sites in PreRequestHook

Important Files Changed

Filename Overview
plugins/governance/main.go Extracts publishRoutingAllowlist and adds model-level filtering to the routing allowlist; the simple IsAllowed check diverges from loadBalanceProvider's catalog-aware IsModelAllowedForProvider for provider-prefixed allowed_models entries and the ["*"] case.

Reviews (1): Last reviewed commit: "fix: routing governance allowlsit fixes" | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/governance/main.go`:
- Around line 613-620: The current loop in main.go treats each ProviderConfig
independently and can include a provider if any config allows the model, but
loadBalanceProvider treats a provider as blocked if any config blacklists the
model. Fix by aggregating per provider: iterate virtualKey.ProviderConfigs and
build per-provider flags (hasAllowed, hasBlacklisted); then for each provider,
if modelStr=="" include it; otherwise exclude the provider if hasBlacklisted is
true; include the provider only if hasAllowed is true and hasBlacklisted is
false (so a single blacklist across any config blocks the provider, matching
loadBalanceProvider behavior). Use the same identifiers:
virtualKey.ProviderConfigs, pc.AllowedModels.IsAllowed,
pc.BlacklistedModels.IsBlocked, and produce the final allowed slice of
schemas.ModelProvider accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cead6a04-41ef-4dad-8dc6-0a702f6860f7

📥 Commits

Reviewing files that changed from the base of the PR and between a273755 and bd0db20.

📒 Files selected for processing (1)
  • plugins/governance/main.go

Comment thread plugins/governance/main.go
Comment thread plugins/governance/main.go
Comment thread plugins/governance/main.go

akshaydeo commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jun 9, 6:28 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 9, 6:29 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit b9f1dfa into dev Jun 9, 2026
14 of 15 checks passed
@akshaydeo
akshaydeo deleted the 06-09-fix_routing_governance_allowlsit_fixes branch June 9, 2026 18:29
akshaydeo pushed a commit that referenced this pull request Jun 12, 2026
…publishing VK provider allowlist (#4221)

## Summary

The routing allowlist published to `BifrostContextKeyRoutingAllowedProviders` previously included all providers on a virtual key regardless of their `allowed_models` / `blocked_models` configuration. This meant a downstream routing layer (load balancing, model-catalog resolution) could select a provider that the VK explicitly forbids for the requested model. This PR fixes that by filtering the allowlist against the model being routed before publishing it.

## Changes

- Extracted the allowlist-publishing logic into a dedicated `publishRoutingAllowlist` method that filters each provider config against the resolved model using `AllowedModels.IsAllowed` / `BlacklistedModels.IsBlocked` before adding it to the allowed set.
- Removed the previous inline allowlist construction in `PreRequestHook`, which unconditionally included every provider on the VK without any model-level filtering.
- `publishRoutingAllowlist` is now called after routing rules have been applied (so the model is in its final post-routing state) for both the large-payload path (using `ParseModelString` on `LargePayloadMetadata.Model`) and the standard path (using `req.GetRequestFields()`).
- An empty allowed slice continues to mean "no provider is permitted," preserving the existing fail-closed behaviour enforced by the empty-provider validation in `handleRequest`.
- A `nil` virtual key is a no-op, so unauthenticated or VK-less requests are unaffected.

## Type of change

- [x] Bug fix

## Affected areas

- [x] Plugins

## How to test

```sh
go test ./...
```

1. Configure a virtual key with two providers where one provider has `allowed_models` that excludes the requested model.
2. Send a request for that model and confirm the excluded provider is never selected by the load balancer or model-catalog resolver.
3. Confirm that a request for a model permitted by both providers can still be routed to either.
4. Confirm that a request where no provider permits the model fails closed rather than falling through to a forbidden provider.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

This tightens provider selection enforcement on virtual keys. Previously, a model-level restriction on a VK provider config could be bypassed by a downstream routing layer picking that provider after governance failed to select one. That bypass path is now closed.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved consistency between routing rule application and provider allowlist enforcement for virtual keys with model restrictions, ensuring correct provider filtering is applied after routing decisions are made.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
akhsaul pushed a commit to akhsaul/bifrost that referenced this pull request Aug 27, 2026
…publishing VK provider allowlist (maximhq#4221)

## Summary

The routing allowlist published to `BifrostContextKeyRoutingAllowedProviders` previously included all providers on a virtual key regardless of their `allowed_models` / `blocked_models` configuration. This meant a downstream routing layer (load balancing, model-catalog resolution) could select a provider that the VK explicitly forbids for the requested model. This PR fixes that by filtering the allowlist against the model being routed before publishing it.

## Changes

- Extracted the allowlist-publishing logic into a dedicated `publishRoutingAllowlist` method that filters each provider config against the resolved model using `AllowedModels.IsAllowed` / `BlacklistedModels.IsBlocked` before adding it to the allowed set.
- Removed the previous inline allowlist construction in `PreRequestHook`, which unconditionally included every provider on the VK without any model-level filtering.
- `publishRoutingAllowlist` is now called after routing rules have been applied (so the model is in its final post-routing state) for both the large-payload path (using `ParseModelString` on `LargePayloadMetadata.Model`) and the standard path (using `req.GetRequestFields()`).
- An empty allowed slice continues to mean "no provider is permitted," preserving the existing fail-closed behaviour enforced by the empty-provider validation in `handleRequest`.
- A `nil` virtual key is a no-op, so unauthenticated or VK-less requests are unaffected.

## Type of change

- [x] Bug fix

## Affected areas

- [x] Plugins

## How to test

```sh
go test ./...
```

1. Configure a virtual key with two providers where one provider has `allowed_models` that excludes the requested model.
2. Send a request for that model and confirm the excluded provider is never selected by the load balancer or model-catalog resolver.
3. Confirm that a request for a model permitted by both providers can still be routed to either.
4. Confirm that a request where no provider permits the model fails closed rather than falling through to a forbidden provider.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

This tightens provider selection enforcement on virtual keys. Previously, a model-level restriction on a VK provider config could be bypassed by a downstream routing layer picking that provider after governance failed to select one. That bypass path is now closed.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved consistency between routing rule application and provider allowlist enforcement for virtual keys with model restrictions, ensuring correct provider filtering is applied after routing decisions are made.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
occcat pushed a commit to occcat/bifrost that referenced this pull request Sep 2, 2026
…publishing VK provider allowlist (maximhq#4221)

## Summary

The routing allowlist published to `BifrostContextKeyRoutingAllowedProviders` previously included all providers on a virtual key regardless of their `allowed_models` / `blocked_models` configuration. This meant a downstream routing layer (load balancing, model-catalog resolution) could select a provider that the VK explicitly forbids for the requested model. This PR fixes that by filtering the allowlist against the model being routed before publishing it.

## Changes

- Extracted the allowlist-publishing logic into a dedicated `publishRoutingAllowlist` method that filters each provider config against the resolved model using `AllowedModels.IsAllowed` / `BlacklistedModels.IsBlocked` before adding it to the allowed set.
- Removed the previous inline allowlist construction in `PreRequestHook`, which unconditionally included every provider on the VK without any model-level filtering.
- `publishRoutingAllowlist` is now called after routing rules have been applied (so the model is in its final post-routing state) for both the large-payload path (using `ParseModelString` on `LargePayloadMetadata.Model`) and the standard path (using `req.GetRequestFields()`).
- An empty allowed slice continues to mean "no provider is permitted," preserving the existing fail-closed behaviour enforced by the empty-provider validation in `handleRequest`.
- A `nil` virtual key is a no-op, so unauthenticated or VK-less requests are unaffected.

## Type of change

- [x] Bug fix

## Affected areas

- [x] Plugins

## How to test

```sh
go test ./...
```

1. Configure a virtual key with two providers where one provider has `allowed_models` that excludes the requested model.
2. Send a request for that model and confirm the excluded provider is never selected by the load balancer or model-catalog resolver.
3. Confirm that a request for a model permitted by both providers can still be routed to either.
4. Confirm that a request where no provider permits the model fails closed rather than falling through to a forbidden provider.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

This tightens provider selection enforcement on virtual keys. Previously, a model-level restriction on a VK provider config could be bypassed by a downstream routing layer picking that provider after governance failed to select one. That bypass path is now closed.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved consistency between routing rule application and provider allowlist enforcement for virtual keys with model restrictions, ensuring correct provider filtering is applied after routing decisions are made.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants