mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-24 01:04:49 -06:00
0e69dbba20
The schema of the input document for the authorization policy is known to OPA. This feature leverages that to perform automatic type checking on the authorization policy. The checks happen on policies provided to OPA on start-up and also those provided via bundles. This check is enabled by default and can be disabled using the `--skip-known-schema-check` flag on `opa run`. This feature will help catch errors such as typos, mismatch types etc. in these policies and provide precise feedback to the policy author. Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
139 lines
2.5 KiB
Go
139 lines
2.5 KiB
Go
// Copyright 2023 The OPA Authors. All rights reserved.
|
|
// Use of this source code is governed by an Apache2
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package compiler
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/open-policy-agent/opa/ast"
|
|
)
|
|
|
|
func TestVerifyAuthorizationPolicySchema(t *testing.T) {
|
|
|
|
module1 := `
|
|
package policy
|
|
|
|
import future.keywords
|
|
|
|
default allow := false
|
|
|
|
allow {
|
|
input.identity = "foo"
|
|
}
|
|
|
|
allow {
|
|
input.client_certificates[0] = {"foo": "bar"}
|
|
}
|
|
|
|
allow {
|
|
input.method = "GET"
|
|
}
|
|
|
|
allow {
|
|
input.path = ["foo", "bar"]
|
|
}
|
|
|
|
allow {
|
|
"foo" in input.path
|
|
}
|
|
|
|
allow {
|
|
input.params = {"foo": "bar"}
|
|
}
|
|
|
|
allow {
|
|
input.headers = {"foo": "bar"}
|
|
}
|
|
|
|
allow {
|
|
input.body.input.stock = "ACME"
|
|
}`
|
|
|
|
module2 := `
|
|
package policy
|
|
|
|
default allow := false
|
|
|
|
allow {
|
|
input.identty = "foo"
|
|
}
|
|
|
|
allow {
|
|
input.path = "foo"
|
|
}`
|
|
|
|
module3 := `
|
|
package policy
|
|
|
|
default allow := false
|
|
|
|
allow {
|
|
input.path = [1, 2, 3]
|
|
}`
|
|
|
|
module4 := `
|
|
package policy
|
|
|
|
default allow := false
|
|
|
|
allow {
|
|
input.client_certificates[0] = "foo"
|
|
}`
|
|
|
|
tests := []struct {
|
|
note string
|
|
modules []string
|
|
wantErr bool
|
|
errs []string
|
|
}{
|
|
{note: "no rules", modules: []string{}},
|
|
{note: "no error", modules: []string{module1}},
|
|
{note: "multiple errors", modules: []string{module2}, wantErr: true, errs: []string{"match error", "undefined ref: input.identty"}},
|
|
{note: "wrong item type path", modules: []string{module3}, wantErr: true, errs: []string{"match error"}},
|
|
{note: "wrong item type certs", modules: []string{module4}, wantErr: true, errs: []string{"match error"}},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.note, func(t *testing.T) {
|
|
modules := map[string]*ast.Module{}
|
|
|
|
for i, module := range tc.modules {
|
|
mod, err := ast.ParseModule(fmt.Sprintf("test%d.rego", i+1), module)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
modules[fmt.Sprintf("test%d.rego", i+1)] = mod
|
|
}
|
|
|
|
c := ast.NewCompiler()
|
|
c.Compile(modules)
|
|
if c.Failed() {
|
|
t.Fatal("unexpected error:", c.Errors)
|
|
}
|
|
|
|
err := VerifyAuthorizationPolicySchema(c, ast.MustParseRef("data.policy.allow"))
|
|
|
|
if tc.wantErr {
|
|
if err == nil {
|
|
t.Fatal("Expected error but got nil")
|
|
}
|
|
|
|
for _, e := range tc.errs {
|
|
if !strings.Contains(err.Error(), e) {
|
|
t.Errorf("Expected error %v not found", e)
|
|
}
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|