Skip to content

Commit 0f3f9d6

Browse files
j-fuentesjetstack-bot
authored andcommitted
Handle the existence or not of the preflight_ prefix in rego (#59)
* Helper to check if version support feature Signed-off-by: Jose Fuentes <[email protected]> * Be flexible with preflight_ preflix Signed-off-by: Jose Fuentes <[email protected]>
1 parent 3c1a781 commit 0f3f9d6

File tree

8 files changed

+255
-6
lines changed

8 files changed

+255
-6
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
cloud.google.com/go/storage v1.4.0
77
github.com/Azure/aks-engine v0.43.1
88
github.com/aws/aws-sdk-go v1.25.30
9+
github.com/blang/semver v3.5.1+incompatible
910
github.com/gomarkdown/markdown v0.0.0-20191104174740-4d42851d4d5a
1011
github.com/gookit/color v1.2.0
1112
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ github.com/hashicorp/vault v0.11.5/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bA
244244
github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20181106190520-2236f141171e/go.mod h1:VJHHT2SC1tAPrfENQeBhLlb5FbZoKZM+oC/ROmEftz0=
245245
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
246246
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
247+
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
247248
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
248249
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
249250
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -305,9 +306,11 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
305306
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
306307
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
307308
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
309+
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
308310
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
309311
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
310312
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
313+
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
311314
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
312315
github.com/mattn/go-runewidth v0.0.0-20181025052659-b20a3daf6a39/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
313316
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@@ -351,9 +354,11 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB
351354
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
352355
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
353356
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
357+
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
354358
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
355359
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
356360
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
361+
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
357362
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
358363
github.com/open-policy-agent/opa v0.16.0 h1:VGyBInxJkrbZ2yNBGygnevnQFJgf/18ZbohvH7Xu9dw=
359364
github.com/open-policy-agent/opa v0.16.0/go.mod h1:P0xUE/GQAAgnvV537GzA0Ikw4+icPELRT327QJPkaKY=
@@ -463,6 +468,7 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO
463468
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
464469
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
465470
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
471+
github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
466472
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
467473
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
468474
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -630,6 +636,7 @@ gopkg.in/asn1-ber.v1 v1.0.0-20170511165959-379148ca0225/go.mod h1:cuepJuh7vyXfUy
630636
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
631637
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
632638
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
639+
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
633640
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
634641
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
635642
gopkg.in/go-playground/validator.v9 v9.25.0 h1:Q3c4LgUofOEtz0wCE18Q2qwDkATLHLBUOmTvqjNCWkM=
@@ -644,6 +651,7 @@ gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5/go.mod h1:hiOFpYm0ZJb
644651
gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
645652
gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
646653
gopkg.in/src-d/go-git.v4 v4.8.1/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk=
654+
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
647655
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
648656
gopkg.in/vmihailenco/msgpack.v2 v2.9.1/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8=
649657
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=

pkg/exporter/exporter.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@ const (
3232
)
3333

3434
func ruleToResult(ruleID string) string {
35-
return fmt.Sprintf("preflight_%s", strings.ReplaceAll(ruleID, ".", "_"))
35+
return strings.ReplaceAll(ruleID, ".", "_")
3636
}
3737

3838
func resultToRule(resultID string) string {
39-
return strings.TrimPrefix(strings.ReplaceAll(resultID, "_", "."), "preflight.")
39+
return strings.ReplaceAll(resultID, "_", ".")
40+
}
41+
42+
func legacyRuleToResult(ruleID string) string {
43+
return fmt.Sprintf("preflight_%s", strings.ReplaceAll(ruleID, ".", "_"))
4044
}

pkg/exporter/exporter_test.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,22 @@ import (
55
)
66

77
func TestRuleToResult(t *testing.T) {
8+
rule := "something_1.2.3"
9+
expectedResult := "something_1_2_3"
10+
if ruleToResult(rule) != expectedResult {
11+
t.Errorf(
12+
"Expected rule %q to render as result %q, but got %q",
13+
rule,
14+
expectedResult,
15+
ruleToResult(rule),
16+
)
17+
}
18+
}
19+
20+
func TestLegacyRuleToResult(t *testing.T) {
821
rule := "1.2.3"
922
expectedResult := "preflight_1_2_3"
10-
if ruleToResult(rule) != expectedResult {
23+
if legacyRuleToResult(rule) != expectedResult {
1124
t.Errorf(
1225
"Expected rule %q to render as result %q, but got %q",
1326
rule,
@@ -18,8 +31,8 @@ func TestRuleToResult(t *testing.T) {
1831
}
1932

2033
func TestResultToRule(t *testing.T) {
21-
result := "preflight_1_3_3"
22-
expectedRule := "1.3.3"
34+
result := "something_1_3_3"
35+
expectedRule := "something.1.3.3"
2336
if resultToRule(result) != expectedRule {
2437
t.Errorf(
2538
"Expected result %q to render as rule %q, but got %q",

pkg/exporter/json.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ func (e *JSONExporter) Export(ctx context.Context, policyManifest *packaging.Pol
5050

5151
results := rc.ByID()
5252
result := results[ruleToResult(rule.ID)]
53+
54+
if result == nil {
55+
supportsPrefix, err := policyManifest.SupportsPreflightPrefix()
56+
if err != nil {
57+
return nil, err
58+
}
59+
60+
if supportsPrefix {
61+
result = results[legacyRuleToResult(rule.ID)]
62+
}
63+
}
64+
5365
var value interface{}
5466
violations := []string{}
5567
success := false

pkg/exporter/json_test.go

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414

1515
func TestJSONExport(t *testing.T) {
1616
pm := &packaging.PolicyManifest{
17-
SchemaVersion: "0.1.0",
17+
SchemaVersion: "0.1.1",
1818
Namespace: "test.org",
1919
ID: "test-pkg",
2020
PackageVersion: "1.2.3",
@@ -48,6 +48,17 @@ func TestJSONExport(t *testing.T) {
4848
"http://jetstack.io/docs2",
4949
},
5050
},
51+
packaging.Rule{
52+
ID: "r3",
53+
Name: "Another rule",
54+
Description: "This is another rule.",
55+
Manual: false,
56+
Remediation: "No remedy.",
57+
Links: []string{
58+
"http://jetstack.io/docs",
59+
"http://jetstack.io/docs2",
60+
},
61+
},
5162
},
5263
},
5364
packaging.Section{
@@ -76,6 +87,7 @@ func TestJSONExport(t *testing.T) {
7687
rc := &results.ResultCollection{
7788
&results.Result{ID: ruleToResult("r1"), Violations: []string{}},
7889
&results.Result{ID: ruleToResult("r2"), Violations: []string{"violation"}},
90+
&results.Result{ID: "preflight_r3", Violations: []string{"another violation"}},
7991
}
8092

8193
expectedJSON := `{
@@ -109,6 +121,19 @@ func TestJSONExport(t *testing.T) {
109121
"description": "This is another rule.",
110122
"name": "Another rule",
111123
"id": "r2"
124+
},
125+
{
126+
"missing": true,
127+
"success": false,
128+
"violations": [],
129+
"links": [
130+
"http://jetstack.io/docs",
131+
"http://jetstack.io/docs2"
132+
],
133+
"remediation": "No remedy.",
134+
"description": "This is another rule.",
135+
"name": "Another rule",
136+
"id": "r3"
112137
}
113138
],
114139
"description": "This is a section.",
@@ -177,3 +202,131 @@ func TestJSONExport(t *testing.T) {
177202
t.Fatalf("got != want: %v", differences)
178203
}
179204
}
205+
206+
func TestJSONExportBackwardsCompatibility(t *testing.T) {
207+
pm := &packaging.PolicyManifest{
208+
SchemaVersion: "0.1.0",
209+
Namespace: "test.org",
210+
ID: "test-pkg",
211+
PackageVersion: "1.2.3",
212+
Name: "Test Package",
213+
Description: "This is a test package.",
214+
Sections: []packaging.Section{
215+
packaging.Section{
216+
ID: "section-1",
217+
Name: "Sample section",
218+
Description: "This is a section.",
219+
Rules: []packaging.Rule{
220+
packaging.Rule{
221+
ID: "r1",
222+
Name: "A rule",
223+
Description: "This is a rule.",
224+
Manual: false,
225+
Remediation: "No remedy.",
226+
Links: []string{
227+
"http://jetstack.io/docs",
228+
"http://jetstack.io/docs2",
229+
},
230+
},
231+
packaging.Rule{
232+
ID: "r2",
233+
Name: "Another rule",
234+
Description: "This is another rule.",
235+
Manual: false,
236+
Remediation: "No remedy.",
237+
Links: []string{
238+
"http://jetstack.io/docs",
239+
"http://jetstack.io/docs2",
240+
},
241+
},
242+
},
243+
},
244+
},
245+
}
246+
247+
jsonExporter := JSONExporter{}
248+
249+
rc := &results.ResultCollection{
250+
&results.Result{ID: ruleToResult("r1"), Violations: []string{}},
251+
&results.Result{ID: legacyRuleToResult("r2"), Violations: []string{"violation"}},
252+
}
253+
254+
expectedJSON := `{
255+
"sections": [
256+
{
257+
"rules": [
258+
{
259+
"missing": false,
260+
"success": true,
261+
"violations": [],
262+
"links": [
263+
"http://jetstack.io/docs",
264+
"http://jetstack.io/docs2"
265+
],
266+
"remediation": "No remedy.",
267+
"description": "This is a rule.",
268+
"name": "A rule",
269+
"id": "r1"
270+
},
271+
{
272+
"missing": false,
273+
"success": false,
274+
"violations": [
275+
"violation"
276+
],
277+
"links": [
278+
"http://jetstack.io/docs",
279+
"http://jetstack.io/docs2"
280+
],
281+
"remediation": "No remedy.",
282+
"description": "This is another rule.",
283+
"name": "Another rule",
284+
"id": "r2"
285+
}
286+
],
287+
"description": "This is a section.",
288+
"name": "Sample section",
289+
"id": "section-1"
290+
}
291+
],
292+
"description": "This is a test package.",
293+
"name": "Test Package",
294+
"package": "test-pkg",
295+
"package-information": {
296+
"id": "test-pkg",
297+
"namespace": "test.org",
298+
"version": "1.2.3"
299+
},
300+
"preflight-version": "development",
301+
"cluster": "",
302+
"timestamp": "0001-01-01T00:00:00Z",
303+
"id": ""
304+
}`
305+
306+
buf, err := jsonExporter.Export(context.Background(), pm, nil, rc)
307+
if err != nil {
308+
t.Fatalf("unexpected err: %+v", err)
309+
}
310+
311+
var got, want map[string]interface{}
312+
313+
if err = json.Unmarshal([]byte(expectedJSON), &want); err != nil {
314+
t.Fatalf("%+v", err)
315+
}
316+
317+
if err = json.Unmarshal(buf.Bytes(), &got); err != nil {
318+
t.Fatalf("%+v", err)
319+
}
320+
321+
diff := gojsondiff.New().CompareObjects(want, got)
322+
323+
if diff.Modified() {
324+
f := formatter.NewAsciiFormatter(want, formatter.AsciiFormatterConfig{ShowArrayIndex: true, Coloring: true})
325+
differences, err := f.Format(diff)
326+
if err != nil {
327+
t.Errorf("could not format diff: %+v", err)
328+
}
329+
330+
t.Fatalf("got != want: %v", differences)
331+
}
332+
}

pkg/packaging/versioning.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package packaging
2+
3+
import "github.com/blang/semver"
4+
5+
// SupportsPreflightPrefix returns true if the SchemaVersion used supports rego rules with `preflight_` prefix over the IDs in the policy manifest. That behaviour was deprecated.
6+
func (m *PolicyManifest) SupportsPreflightPrefix() (bool, error) {
7+
// If version is not defined, it is an old package.
8+
if m.SchemaVersion == "" {
9+
return true, nil
10+
}
11+
12+
v010, err := semver.Make("0.1.0")
13+
if err != nil {
14+
panic(err)
15+
}
16+
17+
v, err := semver.Make(m.SchemaVersion)
18+
if err != nil {
19+
return false, err
20+
}
21+
22+
return v.LTE(v010), nil
23+
}

pkg/packaging/versioning_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package packaging
2+
3+
import "testing"
4+
5+
func TestSupportsPreflightPrefix(t *testing.T) {
6+
testCases := []struct {
7+
version string
8+
wantResult bool
9+
wantErr bool
10+
}{
11+
{"", true, false},
12+
{"0.0.1", true, false},
13+
{"0.1.0", true, false},
14+
{"0.1.1", false, false},
15+
{"1.0.0", false, false},
16+
{"not-semver", false, true},
17+
}
18+
19+
for idx, tc := range testCases {
20+
t.Run(string(idx), func(t *testing.T) {
21+
m := &PolicyManifest{SchemaVersion: tc.version}
22+
gotResult, err := m.SupportsPreflightPrefix()
23+
24+
if err != nil && !tc.wantErr {
25+
t.Fatalf("expected error to be nil but got: %+v", err)
26+
} else if err == nil && tc.wantErr {
27+
t.Fatalf("expected to get an error but didn't get one")
28+
}
29+
30+
if gotResult != tc.wantResult {
31+
t.Errorf("expected %s to have compatibility=%v but got compatibility=%v", tc.version, tc.wantResult, gotResult)
32+
}
33+
})
34+
}
35+
}

0 commit comments

Comments
 (0)