Skip to content

Commit 111e1ba

Browse files
Make command to fail if missing Rego definition (#68)
* Make command to fail if missing rego definition Signed-off-by: Jose Fuentes <[email protected]> * Update pkg/reports/reports.go Co-Authored-By: Charlie Egan <[email protected]> Signed-off-by: Jose Fuentes <[email protected]> Co-authored-by: Charlie Egan <[email protected]>
1 parent 160953d commit 111e1ba

File tree

6 files changed

+141
-69
lines changed

6 files changed

+141
-69
lines changed

cmd/check.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/jetstack/preflight/pkg/output/gcs"
2121
"github.com/jetstack/preflight/pkg/packagesources/local"
2222
"github.com/jetstack/preflight/pkg/packaging"
23+
"github.com/jetstack/preflight/pkg/reports"
2324

2425
"github.com/spf13/cobra"
2526
"github.com/spf13/viper"
@@ -307,6 +308,7 @@ func check() {
307308
log.Fatal("No packages were enabled. Use 'enables-packages' option in configuration to enable the packages you want to use.")
308309
}
309310

311+
missingRules := false
310312
for _, pkgID := range enabledPackages {
311313
// Make sure we loaded the package for this.
312314
pkg := packages[pkgID]
@@ -330,7 +332,12 @@ func check() {
330332

331333
rc, err := packaging.EvalPackage(ctx, pkg, input)
332334
if err != nil {
333-
log.Fatalf("Cannot evaluate package %q: %v", manifest.ID, err)
335+
if _, ok := err.(*reports.MissingRegoDefinitionError); ok {
336+
missingRules = true
337+
log.Printf("%+v", err)
338+
} else {
339+
log.Fatalf("Cannot evaluate package %q: %v", manifest.ID, err)
340+
}
334341
}
335342

336343
intermediateBytes, err := json.Marshal(input)
@@ -346,7 +353,11 @@ func check() {
346353
}
347354
}
348355

349-
log.Printf("Done.")
356+
if missingRules {
357+
log.Fatalf("Some of the rules are missing their corresponding Rego definition. See the rest of the log or the reports to see more details.")
358+
} else {
359+
log.Printf("Done.")
360+
}
350361
}
351362

352363
func homeDir() string {

pkg/exporter/json.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,18 @@ func NewJSONExporter() *JSONExporter {
2323
func (e *JSONExporter) Export(ctx context.Context, policyManifest *packaging.PolicyManifest, intermediateJSON []byte, rc *results.ResultCollection) (*bytes.Buffer, error) {
2424
report, err := reports.NewReport(policyManifest, rc)
2525
if err != nil {
26-
return nil, err
26+
if _, ok := err.(*reports.MissingRegoDefinitionError); !ok {
27+
return nil, err
28+
}
2729
}
30+
missingRuleError := err
2831

2932
b, err := json.Marshal(report)
3033
if err != nil {
3134
return nil, err
3235
}
3336

34-
return bytes.NewBuffer(b), nil
37+
return bytes.NewBuffer(b), missingRuleError
3538
}
3639

3740
// FileExtension returns the file extension for this exporter's format

pkg/exporter/json_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/yudai/gojsondiff/formatter"
1010

1111
"github.com/jetstack/preflight/pkg/packaging"
12+
"github.com/jetstack/preflight/pkg/reports"
1213
"github.com/jetstack/preflight/pkg/results"
1314
"github.com/jetstack/preflight/pkg/rules"
1415
)
@@ -178,7 +179,7 @@ func TestJSONExport(t *testing.T) {
178179
}`
179180

180181
buf, err := jsonExporter.Export(context.Background(), pm, nil, rc)
181-
if err != nil {
182+
if _, ok := err.(*reports.MissingRegoDefinitionError); !ok {
182183
t.Fatalf("unexpected err: %+v", err)
183184
}
184185

pkg/packaging/eval.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,5 @@ func EvalPackage(ctx context.Context, pkg Package, input interface{}) (*results.
2727
allResults = append(allResults, rs...)
2828
}
2929

30-
rc, err := results.NewResultCollectionFromRegoResultSet(&allResults)
31-
if err != nil {
32-
return nil, fmt.Errorf("cannot read results from rego: %s", err)
33-
}
34-
35-
return rc, nil
30+
return results.NewResultCollectionFromRegoResultSet(&allResults)
3631
}

pkg/reports/reports.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package reports
22

33
import (
44
"fmt"
5+
"strings"
56

67
"github.com/jetstack/preflight/api"
78
"github.com/jetstack/preflight/pkg/packaging"
@@ -91,6 +92,7 @@ func NewReport(pm *packaging.PolicyManifest, rc *results.ResultCollection) (api.
9192
Sections: make([]api.ReportSection, len(pm.Sections)),
9293
}
9394

95+
missingRules := []string{}
9496
for idxSection, section := range pm.Sections {
9597
report.Sections[idxSection] = api.ReportSection{
9698
ID: section.ID,
@@ -125,6 +127,7 @@ func NewReport(pm *packaging.PolicyManifest, rc *results.ResultCollection) (api.
125127
switch {
126128
case result == nil:
127129
missing = true
130+
missingRules = append(missingRules, rule.ID)
128131
case result.IsFailureState():
129132
success = false
130133
violations = result.Violations
@@ -149,5 +152,21 @@ func NewReport(pm *packaging.PolicyManifest, rc *results.ResultCollection) (api.
149152
}
150153
}
151154

155+
if len(missingRules) > 0 {
156+
return report, &MissingRegoDefinitionError{
157+
pkg: report.Package,
158+
ids: missingRules,
159+
}
160+
}
152161
return report, nil
153162
}
163+
164+
// MissingRegoDefinitionError error to be returned when a rule from the PolicyManifest was not found in Rego.
165+
type MissingRegoDefinitionError struct {
166+
pkg string
167+
ids []string
168+
}
169+
170+
func (e *MissingRegoDefinitionError) Error() string {
171+
return fmt.Sprintf("the following rules from the package %q are missing their Rego definitions: %s", e.pkg, strings.Join(e.ids, ", "))
172+
}

pkg/reports/reports_test.go

Lines changed: 101 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -245,74 +245,117 @@ func TestNewReport(t *testing.T) {
245245
ID: "b_rule",
246246
Name: "My Rule B",
247247
},
248-
{
249-
ID: "c_rule",
250-
Name: "My Rule C (missing)",
251-
},
252248
},
253249
},
254250
},
255251
}
256252

257-
resultCollection := &results.ResultCollection{
258-
&results.Result{ID: rules.RuleToResult("a_rule"), Violations: []string{}},
259-
&results.Result{ID: rules.RuleToResult("b_rule"), Violations: []string{"violation"}},
260-
}
253+
t.Run("returns a report", func(t *testing.T) {
254+
resultCollection := &results.ResultCollection{
255+
&results.Result{ID: rules.RuleToResult("a_rule"), Violations: []string{}},
256+
&results.Result{ID: rules.RuleToResult("b_rule"), Violations: []string{"violation"}},
257+
}
261258

262-
got, err := NewReport(examplePackage, resultCollection)
263-
if err != nil {
264-
t.Fatalf("NewReport returned error: %v", err)
265-
}
259+
got, err := NewReport(examplePackage, resultCollection)
260+
if err != nil {
261+
t.Fatalf("NewReport returned error: %v", err)
262+
}
266263

267-
want := api.Report{
268-
PreflightVersion: version.PreflightVersion,
269-
Package: examplePackage.ID,
270-
PackageInformation: api.PackageInformation{
271-
Namespace: examplePackage.Namespace,
272-
ID: examplePackage.ID,
273-
Version: examplePackage.PackageVersion,
274-
SchemaVersion: examplePackage.SchemaVersion,
275-
},
276-
Name: examplePackage.Name,
277-
Description: examplePackage.Description,
278-
Sections: []api.ReportSection{
279-
api.ReportSection{
280-
ID: "a_section",
281-
Name: "My section",
282-
Rules: []api.ReportRule{
283-
api.ReportRule{
284-
ID: "a_rule",
285-
Name: "My Rule A",
286-
Manual: false,
287-
Success: true,
288-
Missing: false,
289-
Links: []string{},
290-
Violations: []string{},
291-
},
292-
api.ReportRule{
293-
ID: "b_rule",
294-
Name: "My Rule B",
295-
Manual: false,
296-
Success: false,
297-
Missing: false,
298-
Links: []string{},
299-
Violations: []string{"violation"},
264+
want := api.Report{
265+
PreflightVersion: version.PreflightVersion,
266+
Package: examplePackage.ID,
267+
PackageInformation: api.PackageInformation{
268+
Namespace: examplePackage.Namespace,
269+
ID: examplePackage.ID,
270+
Version: examplePackage.PackageVersion,
271+
SchemaVersion: examplePackage.SchemaVersion,
272+
},
273+
Name: examplePackage.Name,
274+
Description: examplePackage.Description,
275+
Sections: []api.ReportSection{
276+
api.ReportSection{
277+
ID: "a_section",
278+
Name: "My section",
279+
Rules: []api.ReportRule{
280+
api.ReportRule{
281+
ID: "a_rule",
282+
Name: "My Rule A",
283+
Manual: false,
284+
Success: true,
285+
Missing: false,
286+
Links: []string{},
287+
Violations: []string{},
288+
},
289+
api.ReportRule{
290+
ID: "b_rule",
291+
Name: "My Rule B",
292+
Manual: false,
293+
Success: false,
294+
Missing: false,
295+
Links: []string{},
296+
Violations: []string{"violation"},
297+
},
300298
},
301-
api.ReportRule{
302-
ID: "c_rule",
303-
Name: "My Rule C (missing)",
304-
Manual: false,
305-
Success: false,
306-
Missing: true,
307-
Links: []string{},
308-
Violations: []string{},
299+
},
300+
},
301+
}
302+
303+
if !reflect.DeepEqual(got, want) {
304+
t.Fatalf("got != want; got=%+v, want=%+v", got, want)
305+
}
306+
})
307+
308+
t.Run("returns error MissingRegoDefinitionError if definition missing", func(t *testing.T) {
309+
resultCollection := &results.ResultCollection{
310+
&results.Result{ID: rules.RuleToResult("a_rule"), Violations: []string{}},
311+
}
312+
313+
got, err := NewReport(examplePackage, resultCollection)
314+
if _, ok := err.(*MissingRegoDefinitionError); !ok {
315+
t.Errorf("expected MissingRegoDefinitionError but got: %v", err)
316+
}
317+
318+
want := api.Report{
319+
PreflightVersion: version.PreflightVersion,
320+
Package: examplePackage.ID,
321+
PackageInformation: api.PackageInformation{
322+
Namespace: examplePackage.Namespace,
323+
ID: examplePackage.ID,
324+
Version: examplePackage.PackageVersion,
325+
SchemaVersion: examplePackage.SchemaVersion,
326+
},
327+
Name: examplePackage.Name,
328+
Description: examplePackage.Description,
329+
Sections: []api.ReportSection{
330+
api.ReportSection{
331+
ID: "a_section",
332+
Name: "My section",
333+
Rules: []api.ReportRule{
334+
api.ReportRule{
335+
ID: "a_rule",
336+
Name: "My Rule A",
337+
Manual: false,
338+
Success: true,
339+
Missing: false,
340+
Links: []string{},
341+
Violations: []string{},
342+
},
343+
api.ReportRule{
344+
ID: "b_rule",
345+
Name: "My Rule B",
346+
Manual: false,
347+
Success: false,
348+
Missing: true,
349+
Links: []string{},
350+
Violations: []string{},
351+
},
309352
},
310353
},
311354
},
312-
},
313-
}
355+
}
314356

315-
if !reflect.DeepEqual(got, want) {
316-
t.Fatalf("got != want; got=%+v, want=%+v", got, want)
317-
}
357+
if !reflect.DeepEqual(got, want) {
358+
t.Fatalf("got != want; got=%+v, want=%+v", got, want)
359+
}
360+
})
318361
}

0 commit comments

Comments
 (0)