mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
Add path conflict checks
Previously there were no checks in place to ensure that base and virtual documents do not overlap. As a result, if users loaded raw JSON and rules into OPA that overlapped, the evaluation results were not well defined. With these changes, we can detect the overlap and reject updates (to policies or data) that would cause inconsistent results. Fixes #1207 Signed-off-by: Torin Sandall <torinsandall@gmail.com>
This commit is contained in:
+13
-1
@@ -973,6 +973,12 @@ func (s *Server) v1DataPatch(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := ast.CheckPathConflicts(s.getCompiler(), storage.NonEmpty(ctx, s.store, txn)); len(err) > 0 {
|
||||
s.store.Abort(ctx, txn)
|
||||
writer.ErrorString(w, http.StatusBadRequest, types.CodeInvalidParameter, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.store.Commit(ctx, txn); err != nil {
|
||||
writer.ErrorAuto(w, err)
|
||||
} else {
|
||||
@@ -1141,6 +1147,12 @@ func (s *Server) v1DataPut(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := ast.CheckPathConflicts(s.getCompiler(), storage.NonEmpty(ctx, s.store, txn)); len(err) > 0 {
|
||||
s.store.Abort(ctx, txn)
|
||||
writer.ErrorString(w, http.StatusBadRequest, types.CodeInvalidParameter, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.store.Commit(ctx, txn); err != nil {
|
||||
writer.ErrorAuto(w, err)
|
||||
} else {
|
||||
@@ -1359,7 +1371,7 @@ func (s *Server) v1PoliciesPut(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
modules[path] = parsedMod
|
||||
|
||||
c := ast.NewCompiler().SetErrorLimit(s.errLimit)
|
||||
c := ast.NewCompiler().SetErrorLimit(s.errLimit).WithPathConflictsCheck(storage.NonEmpty(ctx, s.store, txn))
|
||||
|
||||
m.Timer(metrics.RegoModuleCompile).Start()
|
||||
|
||||
|
||||
@@ -549,6 +549,33 @@ p = true { false }`
|
||||
"message": "storage_write_conflict_error: /a/b"
|
||||
}`},
|
||||
}},
|
||||
{"put base/virtual conflict", []tr{
|
||||
{http.MethodPut, "/policies/testmod", "package x.y\np = 1\nq = 2", 200, ""},
|
||||
{http.MethodPut, "/data/x", `{"y": {"p": "xxx"}}`, 400, `{
|
||||
"code": "invalid_parameter",
|
||||
"message": "1 error occurred: testmod:2: rego_compile_error: conflicting rule for data path x/y/p found"
|
||||
}`},
|
||||
{http.MethodPut, "/data/x/y", `{"p": "xxx"}`, 400, ``},
|
||||
{http.MethodPut, "/data/x/y/p", `"xxx"`, 400, ``},
|
||||
{http.MethodPut, "/data/x/y/p/a", `1`, 400, ``},
|
||||
{http.MethodDelete, "/policies/testmod", "", 200, ""},
|
||||
{http.MethodPut, "/data/x/y/p/a", `1`, 204, ``},
|
||||
{http.MethodPut, "/policies/testmod", "package x.y\np = 1\nq = 2", 400, `{
|
||||
"code": "invalid_parameter",
|
||||
"message": "error(s) occurred while compiling module(s)",
|
||||
"errors": [
|
||||
{
|
||||
"code": "rego_compile_error",
|
||||
"message": "conflicting rule for data path x/y/p found",
|
||||
"location": {
|
||||
"file": "testmod",
|
||||
"row": 2,
|
||||
"col": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
}`},
|
||||
}},
|
||||
{"get virtual", []tr{
|
||||
{http.MethodPut, "/policies/test", testMod1, 200, ""},
|
||||
{http.MethodPatch, "/data/x", `[{"op": "add", "path": "/", "value": {"y": [1,2,3,4], "z": [3,4,5,6]}}]`, 204, ""},
|
||||
|
||||
Reference in New Issue
Block a user