Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion features/__snapshots__/validate_image.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2164,7 +2164,17 @@ Error: success criteria not met
---

[TestFeatures/Dropping rego capabilities:stderr - 1]
Error: error validating image ${REGISTRY}/acceptance/ec-happy-day of component Unnamed: load: loading policies: get compiler: 3 errors occurred:
Error: error validating image ${REGISTRY}/acceptance/ec-happy-day of component Unnamed: policy compilation error: the policy references Rego built-in functions not available in this version of Conforma CLI (v1.15.2).
Comment thread
st3penta marked this conversation as resolved.

Upgrade Conforma CLI to a newer version that includes the required functions.

If upgrading does not help, check for less common causes:
- Conforma CLI disables certain built-in functions for security (opa.runtime, http.send, net.lookup_ip_addr). Policies using these will not compile regardless of the CLI version
- The policy may use Rego syntax requiring a newer OPA version.
Adjust the policy to target OPA v1.15.2 or earlier

Details:
load: loading policies: get compiler: 3 errors occurred:
${TEMP}/ec-work-${RANDOM}/policy/${RANDOM}/main.rego:14: rego_type_error: undefined function opa.runtime
${TEMP}/ec-work-${RANDOM}/policy/${RANDOM}/main.rego:22: rego_type_error: undefined function http.send
${TEMP}/ec-work-${RANDOM}/policy/${RANDOM}/main.rego:33: rego_type_error: undefined function net.lookup_ip_addr
Expand Down
12 changes: 5 additions & 7 deletions internal/evaluator/conftest_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ func (r conftestRunner) Run(ctx context.Context, fileList []string) (result []Ou
var conftestResult []output.CheckResult
conftestResult, err = r.TestRunner.Run(ctx, fileList)
if err != nil {
err = wrapRegoError(err)
return
}

Expand Down Expand Up @@ -268,6 +269,7 @@ func (r conftestRunner) Run(ctx context.Context, fileList []string) (result []Ou
}
engine, err = conftest.LoadWithData(r.Policy, r.Data, compilerOptions)
if err != nil {
err = wrapRegoError(err)
return
}

Expand Down Expand Up @@ -1196,13 +1198,9 @@ func strictCapabilities(ctx context.Context) (string, error) {
log.Debug("Network access from rego policies disabled")

builtins := make([]*ast.Builtin, 0, len(capabilities.Builtins))
disallowed := sets.NewString(
// disallow access to environment variables
"opa.runtime",
// disallow external connections. This is a second layer of defense since
// AllowNet should prevent external connections in the first place.
"http.send", "net.lookup_ip_addr",
)
// disallowedBuiltins is defined in rego_errors.go as the single source of
// truth for security-restricted built-in functions.
disallowed := sets.NewString(disallowedBuiltins...)
for _, b := range capabilities.Builtins {
if !disallowed.Has(b.Name) {
builtins = append(builtins, b)
Expand Down
2 changes: 1 addition & 1 deletion internal/evaluator/opa_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (o *opaEvaluator) compileEngine(ctx context.Context) error {

engine, err := conftest.LoadWithData([]string{o.policyDir}, dataDirs, opts)
if err != nil {
return fmt.Errorf("load: %w", err)
return wrapRegoError(fmt.Errorf("load: %w", err))
Comment thread
st3penta marked this conversation as resolved.
}

engine.EnableInterQueryCache()
Expand Down
97 changes: 97 additions & 0 deletions internal/evaluator/rego_errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright The Conforma Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

package evaluator

import (
"fmt"
dbg "runtime/debug"
"strings"
)

// opaModulePath is the Go module path used to look up the bundled OPA version
// from build info.
const opaModulePath = "github.com/open-policy-agent/opa"

// disallowedBuiltins lists the OPA built-in functions that are disabled by
// strictCapabilities for security reasons. This is the single source of truth
// used by both strictCapabilities (conftest_evaluator.go) and wrapRegoError.
var disallowedBuiltins = []string{
Comment thread
st3penta marked this conversation as resolved.
Comment thread
st3penta marked this conversation as resolved.
"opa.runtime",
"http.send",
"net.lookup_ip_addr",
}

// readBuildInfo is a variable to allow overriding in tests.

var readBuildInfo = dbg.ReadBuildInfo

// isRegoCompilationError checks whether the error message contains OPA/Rego
// compilation error patterns (rego_type_error, rego_parse_error,
// rego_compile_error) that may indicate a version incompatibility or a
// capability restriction.
func isRegoCompilationError(err error) bool {
if err == nil {
return false
}
Comment thread
st3penta marked this conversation as resolved.
msg := err.Error()
return strings.Contains(msg, "rego_type_error") ||
strings.Contains(msg, "rego_parse_error") ||
strings.Contains(msg, "rego_compile_error")
}

// bundledOPAVersion returns the version of the OPA module bundled in this
// binary, or "unknown" if it cannot be determined.
func bundledOPAVersion() string {
info, ok := readBuildInfo()
if !ok {
return "unknown"
}
for _, dep := range info.Deps {
if dep.Path == opaModulePath {
return dep.Version
}
}
return "unknown"
}

// wrapRegoError inspects err for OPA/Rego compilation error patterns
// (rego_type_error, rego_parse_error, rego_compile_error). If found, it wraps
// the error with a user-friendly message that includes the bundled OPA version
// and remediation guidance. Non-matching errors are returned as-is.
func wrapRegoError(err error) error {
if !isRegoCompilationError(err) {
Comment thread
st3penta marked this conversation as resolved.
return err
}

version := bundledOPAVersion()

Comment thread
st3penta marked this conversation as resolved.
versionSuffix := ""
adjustLine := ""
if version != "unknown" {
versionSuffix = " (" + version + ")"
adjustLine = fmt.Sprintf(".\n Adjust the policy to target OPA %s or earlier", version)
}

return fmt.Errorf("policy compilation error: the policy references Rego built-in "+
"functions not available in this version of Conforma CLI%s.\n\n"+
"Upgrade Conforma CLI to a newer version that includes the required functions.\n\n"+
"If upgrading does not help, check for less common causes:\n"+
" - Conforma CLI disables certain built-in functions for security "+
"(%s). Policies using these will not compile regardless of the CLI version\n"+
" - The policy may use Rego syntax requiring a newer OPA version%s\n\n"+
"Details:\n %w", versionSuffix, strings.Join(disallowedBuiltins, ", "), adjustLine, err)
}
Loading
Loading