policy: update unknown keys normalization
Make the code more unified between validation and test command. Normalize to key without the input prefix. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
+14
-15
@@ -311,7 +311,7 @@ func runPolicyTest(ctx context.Context, policyModules map[string]*ast.Module, te
|
||||
result.Allow = allow
|
||||
result.DenyMessages = deny
|
||||
|
||||
missing := missingInputRefs(policyPackageModules, effectiveInput)
|
||||
missing := missingInputRefs(policyPackageModules, effectiveInput, runtimeUnknownInputRefs(testState), runtimeUnknownInputRefs(decisionState))
|
||||
result.MissingInput = uniqueSortedStrings(missing)
|
||||
result.MetadataNeeded = summarizeMetadataRequests(result.MissingInput)
|
||||
|
||||
@@ -534,7 +534,7 @@ func hasEnv(env Env) bool {
|
||||
func filterResolvableMissing(missing []string) []string {
|
||||
out := make([]string, 0, len(missing))
|
||||
for _, m := range missing {
|
||||
if strings.HasPrefix(m, "input.image.") || strings.HasPrefix(m, "input.git.") {
|
||||
if strings.HasPrefix(m, "image.") || strings.HasPrefix(m, "git.") {
|
||||
out = append(out, m)
|
||||
}
|
||||
}
|
||||
@@ -595,24 +595,27 @@ func modulesForPackage(modules map[string]*ast.Module, pkgPath string) []*ast.Mo
|
||||
return out
|
||||
}
|
||||
|
||||
func missingInputRefs(mods []*ast.Module, input *Input) []string {
|
||||
func missingInputRefs(mods []*ast.Module, input *Input, extraRefs ...[]string) []string {
|
||||
if len(mods) == 0 {
|
||||
return nil
|
||||
}
|
||||
inputMap := normalizeInput(input)
|
||||
refs := collectUnknowns(mods, nil)
|
||||
for _, er := range extraRefs {
|
||||
refs = append(refs, er...)
|
||||
}
|
||||
seen := map[string]struct{}{}
|
||||
missing := make([]string, 0, len(refs))
|
||||
for _, ref := range refs {
|
||||
key := strings.TrimPrefix(ref, "input.")
|
||||
if key == ref {
|
||||
continue
|
||||
}
|
||||
key = trimKey(key)
|
||||
for _, key := range refs {
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[key]; ok {
|
||||
continue
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
if !inputHasPath(inputMap, strings.Split(key, ".")) {
|
||||
missing = append(missing, "input."+key)
|
||||
missing = append(missing, key)
|
||||
}
|
||||
}
|
||||
return missing
|
||||
@@ -703,11 +706,7 @@ func summarizeMetadataRequests(missing []string) []string {
|
||||
return nil
|
||||
}
|
||||
req := &gwpb.ResolveSourceMetaRequest{}
|
||||
trimmed := make([]string, 0, len(missing))
|
||||
for _, m := range missing {
|
||||
trimmed = append(trimmed, strings.TrimPrefix(m, "input."))
|
||||
}
|
||||
if err := AddUnknowns(req, trimmed); err != nil {
|
||||
if err := AddUnknowns(req, missing); err != nil {
|
||||
return nil
|
||||
}
|
||||
var out []string
|
||||
|
||||
@@ -3,6 +3,7 @@ package policy
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/open-policy-agent/opa/v1/ast"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -18,12 +19,16 @@ func TestTrimKey(t *testing.T) {
|
||||
// one separator → stays as-is
|
||||
{"git.tag", "git.tag"},
|
||||
{"git[tag", "git[tag"},
|
||||
{"input.git.tag", "git.tag"},
|
||||
{"input.git[tag", "git[tag"},
|
||||
|
||||
// multiple separators → cut before second one
|
||||
{"git.tag.author", "git.tag"},
|
||||
{"git.tag.author.email", "git.tag"},
|
||||
{"git.tag[0][1]", "git.tag"},
|
||||
{"git.tag[0]", "git.tag"},
|
||||
{"input.git.tag.author", "git.tag"},
|
||||
{"input.git.tag[0]", "git.tag"},
|
||||
|
||||
{"a.b.c", "a.b"},
|
||||
}
|
||||
@@ -34,3 +39,51 @@ func TestTrimKey(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectUnknowns(t *testing.T) {
|
||||
mod, err := ast.ParseModule("x.rego", `
|
||||
package x
|
||||
p if {
|
||||
input.git.tag[0].author == "a"
|
||||
input.image.signatures[_].signer.certificateIssuer != ""
|
||||
data.foo.bar == 1
|
||||
}
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
|
||||
all := collectUnknowns([]*ast.Module{mod}, nil)
|
||||
require.ElementsMatch(t, []string{"git.tag", "image.signatures"}, all)
|
||||
|
||||
filtered := collectUnknowns([]*ast.Module{mod}, []string{"input.image.signatures"})
|
||||
require.Equal(t, []string{"image.signatures"}, filtered)
|
||||
}
|
||||
|
||||
func TestRuntimeUnknownInputRefs(t *testing.T) {
|
||||
require.Nil(t, runtimeUnknownInputRefs(nil))
|
||||
require.Nil(t, runtimeUnknownInputRefs(&state{}))
|
||||
|
||||
st := &state{
|
||||
Unknowns: map[string]struct{}{
|
||||
funcVerifyGitSignature: {},
|
||||
},
|
||||
}
|
||||
require.Equal(t, []string{"git.commit"}, runtimeUnknownInputRefs(st))
|
||||
}
|
||||
|
||||
func TestMissingInputRefsWithRuntimeUnknowns(t *testing.T) {
|
||||
mod, err := ast.ParseModule("x.rego", `
|
||||
package x
|
||||
p if {
|
||||
input.git.ref != ""
|
||||
}
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
|
||||
in := &Input{
|
||||
Git: &Git{
|
||||
Ref: "refs/heads/main",
|
||||
},
|
||||
}
|
||||
missing := missingInputRefs([]*ast.Module{mod}, in, []string{"git.commit"})
|
||||
require.Equal(t, []string{"git.commit"}, missing)
|
||||
}
|
||||
|
||||
+28
-13
@@ -224,9 +224,7 @@ func (p *Policy) CheckPolicy(ctx context.Context, req *policysession.CheckPolicy
|
||||
return nil, nil, err
|
||||
}
|
||||
unk := collectUnknowns(pq.Support, unknowns)
|
||||
if _, ok := st.Unknowns[funcVerifyGitSignature]; ok {
|
||||
unk = append(unk, "input.git.commit")
|
||||
}
|
||||
unk = append(unk, runtimeUnknownInputRefs(st)...)
|
||||
|
||||
if len(unk) > 0 {
|
||||
next := &gwpb.ResolveSourceMetaRequest{
|
||||
@@ -621,14 +619,12 @@ func AddUnknowns(req *gwpb.ResolveSourceMetaRequest, unk []string) error {
|
||||
func AddUnknownsWithLogger(logf func(logrus.Level, string), req *gwpb.ResolveSourceMetaRequest, unk []string) error {
|
||||
unk2 := make([]string, 0, len(unk))
|
||||
for _, u := range unk {
|
||||
k := strings.TrimPrefix(u, "input.")
|
||||
k = trimKey(k)
|
||||
switch k {
|
||||
switch u {
|
||||
case "image", "git", "http", "local":
|
||||
// parents are returned as unknowns for some reason, ignore
|
||||
continue
|
||||
default:
|
||||
unk2 = append(unk2, k)
|
||||
unk2 = append(unk2, u)
|
||||
}
|
||||
}
|
||||
if len(unk2) == 0 {
|
||||
@@ -680,8 +676,10 @@ func collectUnknowns(mods []*ast.Module, allowed []string) []string {
|
||||
for _, mod := range mods {
|
||||
ast.WalkRefs(mod, func(ref ast.Ref) bool {
|
||||
if ref.HasPrefix(ast.InputRootRef) {
|
||||
s := ref.String() // e.g. "input.request.path"
|
||||
s = "input." + trimKey(strings.TrimPrefix(s, "input."))
|
||||
s := trimKey(ref.String())
|
||||
if s == "" {
|
||||
return true
|
||||
}
|
||||
if _, ok := seen[s]; !ok {
|
||||
seen[s] = struct{}{}
|
||||
out = append(out, s)
|
||||
@@ -696,6 +694,10 @@ func collectUnknowns(mods []*ast.Module, allowed []string) []string {
|
||||
|
||||
valid := map[string]struct{}{}
|
||||
for _, k := range allowed {
|
||||
k = trimKey(k)
|
||||
if k == "" {
|
||||
continue
|
||||
}
|
||||
valid[k] = struct{}{}
|
||||
}
|
||||
|
||||
@@ -709,14 +711,25 @@ func collectUnknowns(mods []*ast.Module, allowed []string) []string {
|
||||
return filtered
|
||||
}
|
||||
|
||||
func runtimeUnknownInputRefs(st *state) []string {
|
||||
if st == nil || len(st.Unknowns) == 0 {
|
||||
return nil
|
||||
}
|
||||
var out []string
|
||||
if _, ok := st.Unknowns[funcVerifyGitSignature]; ok {
|
||||
out = append(out, "git.commit")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func summarizeUnknownsForLog(unk []string) []string {
|
||||
out := make([]string, 0, len(unk))
|
||||
seen := map[string]struct{}{}
|
||||
for _, u := range unk {
|
||||
if strings.HasPrefix(u, "input.image.signatures") {
|
||||
u = "input.image.signatures"
|
||||
if strings.HasPrefix(u, "image.signatures") {
|
||||
u = "image.signatures"
|
||||
}
|
||||
if u == "input.image" {
|
||||
if u == "image" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[u]; ok {
|
||||
@@ -730,7 +743,7 @@ func summarizeUnknownsForLog(unk []string) []string {
|
||||
|
||||
func hasHTTPUnknowns(unk []string) bool {
|
||||
for _, u := range unk {
|
||||
if strings.HasPrefix(u, "input.http.") {
|
||||
if strings.HasPrefix(u, "http.") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -738,6 +751,8 @@ func hasHTTPUnknowns(unk []string) bool {
|
||||
}
|
||||
|
||||
func trimKey(s string) string {
|
||||
s = strings.TrimPrefix(s, "input.")
|
||||
|
||||
const (
|
||||
dot = '.'
|
||||
sb = '['
|
||||
|
||||
Reference in New Issue
Block a user