Skip to content

Commit 0ecbc1d

Browse files
Add reasons
1 parent d89486c commit 0ecbc1d

File tree

3 files changed

+116
-13
lines changed

3 files changed

+116
-13
lines changed

pkg/validation/policy.go

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io/ioutil"
77
"path/filepath"
88
"reflect"
9+
"strings"
910

1011
"github.com/ghodss/yaml"
1112
"github.com/open-policy-agent/opa/rego"
@@ -14,6 +15,7 @@ import (
1415
const (
1516
defaultPackage = "com.segment.kubeapply"
1617
defaultResult = "deny"
18+
warnPrefix = "warn:"
1719
)
1820

1921
// Policy wraps a policy module and a prepared query.
@@ -155,12 +157,53 @@ func (p *PolicyChecker) Check(ctx context.Context, resource Resource) CheckResul
155157
result.Status = StatusValid
156158
result.Message = "Policy returned 0 deny reasons"
157159
} else {
158-
result.Status = StatusInvalid
159-
result.Message = fmt.Sprintf(
160-
"Policy returned %d deny reason(s): %+v",
161-
len(value),
162-
value,
163-
)
160+
invalidReasons := []string{}
161+
warnReasons := []string{}
162+
163+
for _, subValue := range value {
164+
subValueStr := fmt.Sprintf("%v", subValue)
165+
166+
if strings.HasPrefix(
167+
strings.ToLower(subValueStr),
168+
warnPrefix,
169+
) {
170+
// Treat this as a warning
171+
warnReasons = append(
172+
warnReasons,
173+
subValueStr,
174+
)
175+
} else {
176+
// Treat this as a denial
177+
invalidReasons = append(
178+
invalidReasons,
179+
subValueStr,
180+
)
181+
}
182+
}
183+
184+
if len(invalidReasons) == 0 {
185+
result.Status = StatusWarning
186+
result.Message = fmt.Sprintf(
187+
"Policy returned %d warn reason(s)",
188+
len(warnReasons),
189+
)
190+
result.Reasons = warnReasons
191+
} else if len(warnReasons) == 0 {
192+
result.Status = StatusInvalid
193+
result.Message = fmt.Sprintf(
194+
"Policy returned %d deny reason(s)",
195+
len(invalidReasons),
196+
)
197+
result.Reasons = invalidReasons
198+
} else {
199+
result.Status = StatusInvalid
200+
result.Message = fmt.Sprintf(
201+
"Policy returned %d deny reason(s) and %d warn reason(s)",
202+
len(invalidReasons),
203+
len(warnReasons),
204+
)
205+
result.Reasons = append(invalidReasons, warnReasons...)
206+
}
164207
}
165208
default:
166209
result.Status = StatusError

pkg/validation/policy_test.go

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,17 @@ package example
1414
1515
deny[msg] {
1616
input.apiVersion == "badVersion"
17-
input.extraKey == "extraBadValue"
1817
msg = "Cannot have bad api version"
18+
}
19+
20+
deny[msg] {
21+
input.extraKey == "extraBadValue"
22+
msg = "Cannot have bad extra key"
23+
}
24+
25+
deny[msg] {
26+
input.extraKey2 == "warnValue"
27+
msg = "WARN: Cannot have warn value"
1928
}`
2029

2130
allowPolicyStr = `
@@ -56,9 +65,6 @@ func TestPolicyChecker(t *testing.T) {
5665
Contents: denyPolicyStr,
5766
Package: "example",
5867
Result: "deny",
59-
ExtraFields: map[string]interface{}{
60-
"extraKey": "extraBadValue",
61-
},
6268
},
6369
resource: MakeResource("test/path", []byte(goodVersionResourceStr), 0),
6470
expected: CheckResult{
@@ -82,8 +88,32 @@ func TestPolicyChecker(t *testing.T) {
8288
expected: CheckResult{
8389
CheckType: CheckTypeOPA,
8490
CheckName: "testDenyPolicy",
85-
Status: StatusValid,
86-
Message: "Policy returned 0 deny reasons",
91+
Status: StatusInvalid,
92+
Message: "Policy returned 1 deny reason(s)",
93+
Reasons: []string{
94+
"Cannot have bad api version",
95+
},
96+
},
97+
},
98+
{
99+
policyModule: PolicyModule{
100+
Name: "testDenyPolicy",
101+
Contents: denyPolicyStr,
102+
Package: "example",
103+
Result: "deny",
104+
ExtraFields: map[string]interface{}{
105+
"extraKey2": "warnValue",
106+
},
107+
},
108+
resource: MakeResource("test/path", []byte(goodVersionResourceStr), 0),
109+
expected: CheckResult{
110+
CheckType: CheckTypeOPA,
111+
CheckName: "testDenyPolicy",
112+
Status: StatusWarning,
113+
Message: "Policy returned 1 warn reason(s)",
114+
Reasons: []string{
115+
"WARN: Cannot have warn value",
116+
},
87117
},
88118
},
89119
{
@@ -101,7 +131,35 @@ func TestPolicyChecker(t *testing.T) {
101131
CheckType: CheckTypeOPA,
102132
CheckName: "testDenyPolicy",
103133
Status: StatusInvalid,
104-
Message: "Policy returned 1 deny reason(s): [Cannot have bad api version]",
134+
Message: "Policy returned 2 deny reason(s)",
135+
Reasons: []string{
136+
"Cannot have bad extra key",
137+
"Cannot have bad api version",
138+
},
139+
},
140+
},
141+
{
142+
policyModule: PolicyModule{
143+
Name: "testDenyPolicy",
144+
Contents: denyPolicyStr,
145+
Package: "example",
146+
Result: "deny",
147+
ExtraFields: map[string]interface{}{
148+
"extraKey": "extraBadValue",
149+
"extraKey2": "warnValue",
150+
},
151+
},
152+
resource: MakeResource("test/path", []byte(badVersionResourceStr), 0),
153+
expected: CheckResult{
154+
CheckType: CheckTypeOPA,
155+
CheckName: "testDenyPolicy",
156+
Status: StatusInvalid,
157+
Message: "Policy returned 2 deny reason(s) and 1 warn reason(s)",
158+
Reasons: []string{
159+
"Cannot have bad extra key",
160+
"Cannot have bad api version",
161+
"WARN: Cannot have warn value",
162+
},
105163
},
106164
},
107165
{

pkg/validation/result.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ type Status string
66
const (
77
StatusValid Status = "valid"
88
StatusInvalid Status = "invalid"
9+
StatusWarning Status = "warning"
910
StatusError Status = "error"
1011
StatusSkipped Status = "skipped"
1112
StatusEmpty Status = "empty"
@@ -31,4 +32,5 @@ type CheckResult struct {
3132
CheckName string
3233
Status Status
3334
Message string
35+
Reasons []string
3436
}

0 commit comments

Comments
 (0)