Skip to content

rego: fail closed on external_data provider errors#705

Open
sozercan wants to merge 1 commit intomasterfrom
codex/fix-external_data-error-handling
Open

rego: fail closed on external_data provider errors#705
sozercan wants to merge 1 commit intomasterfrom
codex/fix-external_data-error-handling

Conversation

@sozercan
Copy link
Copy Markdown
Member

@sozercan sozercan commented Apr 9, 2026

Motivation

  • Fix a fail-open vulnerability where external_data builtin converted provider/cache/TLS/HTTP/JSON errors into a normal Rego response term, allowing constraints to be bypassed if they ignore system_error.

Description

  • Return builtin errors from the Rego external_data implementation instead of encoding failures into a RegoResponse, by replacing externaldata.HandleError(...) with return nil, err in constraint/pkg/client/drivers/rego/builtin.go.
  • Remove the now-unused net/http import from constraint/pkg/client/drivers/rego/builtin.go.
  • Update TestDriver_ExternalData in constraint/pkg/client/drivers/rego/driver_unit_test.go so failure scenarios assert that Query returns a non-nil error while successful responses keep the existing behavior.

Testing

  • Attempted to run the external-data focused unit tests with go test ./pkg/client/drivers/rego -run TestDriver_ExternalData -count=1, but the run timed out in this environment (EXIT:124).
  • Attempted a focused test go test -v ./pkg/client/drivers/rego -run 'TestDriver_ExternalData/provider_not_found' -count=1, which also timed out in this environment (EXIT:124).
  • No other automated tests completed in this environment due to timeouts, but the change is minimal and confined to the builtin error propagation and its unit test expectations.

Codex Task

Copilot AI review requested due to automatic review settings April 9, 2026 19:39
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the Rego external_data builtin to fail closed by propagating provider/cache/TLS/HTTP/JSON failures as builtin errors, preventing policies from bypassing constraints by ignoring system_error.

Changes:

  • Change external_data builtin to return error (instead of encoding failures into a normal Rego response term).
  • Remove the now-unused net/http import from the builtin implementation.
  • Update TestDriver_ExternalData expectations for error scenarios.
Show a summary per file
File Description
constraint/pkg/client/drivers/rego/builtin.go Propagates provider/TLS/request errors as builtin errors (fail closed) and removes unused import.
constraint/pkg/client/drivers/rego/driver_unit_test.go Adjusts external_data unit test expectations for failure scenarios.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 2

Comment on lines +867 to +876
if tt.errorExpected {
if err == nil {
t.Fatalf("got Query() error = nil, want non-nil")
}
return
}
if tt.errorExpected && len(qr.Results) == 0 {
t.Fatalf("got 0 errors on normal query; want 1")
if err != nil {
t.Fatalf("got Query() error = %v, want nil", err)
}
if !tt.errorExpected && len(qr.Results) > 0 {
if len(qr.Results) > 0 {
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

Test expectations no longer match Driver.Query behavior. Query() intentionally converts Rego eval errors into violation results (see driver.go) and still returns a nil error; with external_data now returning an error from the builtin, Query() will likely return err == nil and qr.Results > 0. Update this test to assert on qr.Results (and possibly the msg contents) for failure cases, or change Driver.Query to propagate eval errors if the new contract is intentional.

Copilot uses AI. Check for mistakes.
Comment on lines 64 to +76
provider, err := d.providerCache.Get(regoReq.ProviderName)
if err != nil {
return externaldata.HandleError(http.StatusBadRequest, err)
return nil, err
}

clientCert, err := d.getTLSCertificate()
if err != nil {
return externaldata.HandleError(http.StatusBadRequest, err)
return nil, err
}

externaldataResponse, statusCode, err := d.sendRequestToProvider(bctx.Context, &provider, providerRequestKeys, clientCert)
if err != nil {
return externaldata.HandleError(statusCode, err)
return nil, err
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

Now that external_data errors are propagated as builtin errors (and ultimately surfaced via Query()'s error-to-violation conversion), consider wrapping these returned errors with context like provider name and (for request failures) the HTTP status code. Returning the raw underlying error strings (e.g. "key is not found in provider cache") makes diagnosing which provider/operation failed harder once it reaches users/logs.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@JaydipGabani JaydipGabani left a comment

Choose a reason for hiding this comment

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

This should not be changed, returning rego response was intentional, changing this may break existing behavior.

IMO close this pr without merging.

Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
@sozercan sozercan force-pushed the codex/fix-external_data-error-handling branch from cd40586 to db39515 Compare April 21, 2026 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants