forked from gruntwork-io/terratest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
opa_check.go
90 lines (80 loc) · 3.1 KB
/
opa_check.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package terraform
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/hashicorp/go-multierror"
"github.com/stretchr/testify/require"
"github.com/tmccombs/hcl2json/convert"
"github.com/gruntwork-io/terratest/modules/files"
"github.com/gruntwork-io/terratest/modules/opa"
"github.com/gruntwork-io/terratest/modules/testing"
)
// OPAEval runs `opa eval` with the given option on the terraform files identified in the TerraformDir directory of the
// Options struct. Note that since OPA does not natively support parsing HCL code, we first convert all the files to
// JSON prior to passing it through OPA. This function fails the test if there is an error.
func OPAEval(
t testing.TestingT,
tfOptions *Options,
opaEvalOptions *opa.EvalOptions,
resultQuery string,
) {
require.NoError(t, OPAEvalE(t, tfOptions, opaEvalOptions, resultQuery))
}
// OPAEvalE runs `opa eval` with the given option on the terraform files identified in the TerraformDir directory of the
// Options struct. Note that since OPA does not natively support parsing HCL code, we first convert all the files to
// JSON prior to passing it through OPA.
func OPAEvalE(
t testing.TestingT,
tfOptions *Options,
opaEvalOptions *opa.EvalOptions,
resultQuery string,
) error {
tfOptions.Logger.Logf(t, "Running terraform files in %s through `opa eval` on policy %s", tfOptions.TerraformDir, opaEvalOptions.RulePath)
// Find all the tf files in the terraform dir to process.
tfFiles, err := files.FindTerraformSourceFilesInDir(tfOptions.TerraformDir)
if err != nil {
return err
}
// Create a temporary dir to store all the json files
tmpDir, err := ioutil.TempDir("", "terratest-opa-hcl2json-*")
if err != nil {
return err
}
if !opaEvalOptions.DebugKeepTempFiles {
defer os.RemoveAll(tmpDir)
}
tfOptions.Logger.Logf(t, "Using temporary folder %s for json representation of terraform module %s", tmpDir, tfOptions.TerraformDir)
// Convert all the found tf files to json format so OPA works.
jsonFiles := make([]string, len(tfFiles))
errorsOccurred := new(multierror.Error)
for i, tfFile := range tfFiles {
tfFileBase := filepath.Base(tfFile)
tfFileBaseName := strings.TrimSuffix(tfFileBase, filepath.Ext(tfFileBase))
outPath := filepath.Join(tmpDir, tfFileBaseName+".json")
tfOptions.Logger.Logf(t, "Converting %s to json %s", tfFile, outPath)
if err := HCLFileToJSONFile(tfFile, outPath); err != nil {
errorsOccurred = multierror.Append(errorsOccurred, err)
}
jsonFiles[i] = outPath
}
if err := errorsOccurred.ErrorOrNil(); err != nil {
return err
}
// Run OPA checks on each of the converted json files.
return opa.EvalE(t, opaEvalOptions, jsonFiles, resultQuery)
}
// HCLFileToJSONFile is a function that takes a path containing HCL code, and converts it to JSON representation and
// writes out the contents to the given path.
func HCLFileToJSONFile(hclPath, jsonOutPath string) error {
fileBytes, err := ioutil.ReadFile(hclPath)
if err != nil {
return err
}
converted, err := convert.Bytes(fileBytes, hclPath, convert.Options{})
if err != nil {
return err
}
return ioutil.WriteFile(jsonOutPath, converted, 0600)
}