Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,52 @@
# Configuration

This plugin can take advantage of additional features by configure the plugin block. Currently, this configuration is only available for customizing a policy directory.
This plugin can take advantage of additional features by configure the plugin block. Currently, this configuration is only available for customizing the directories to load policies.

Here's an example:

```hcl
plugin "opa" {
// Plugin common attributes

policy_dir = "./policies"
policy_dirs = ["./policies", "./other-policies"]
}
```

## `policy_dir`
## `policy_dirs`

Default: `./.tflint.d/policies`, `~/.tflint.d/policies`

Change the directory from which policies are loaded. The priority is as follows:
Change the directories from which policies are loaded. You can specify multiple directories to load policies from different locations. The priority is as follows:

1. `policy_dir` in the config
2. `TFLINT_OPA_POLICY_DIR` environment variable
1. `policy_dirs` in the config
2. `TFLINT_OPA_POLICY_DIRS` environment variable (supports multiple directories separated `,`)
3. `./.tflint.d/policies`
4. `~/.tflint.d/policies`

A relative path is resolved from the current directory.

### Examples

Single directory:
```hcl
plugin "opa" {
policy_dirs = ["./policies"]
}
```

Multiple directories:
```hcl
plugin "opa" {
policy_dirs = ["./policies", "./team-policies", "~/shared-policies"]
}
```

Using environment variable with a single directory:
```bash
export TFLINT_OPA_POLICY_DIRS="./policies"
```

Using environment variable with multiple directories:
```bash
export TFLINT_OPA_POLICY_DIRS="./policies,./team-policies,~/shared-policies"
```
4 changes: 2 additions & 2 deletions docs/environment_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Below is a list of environment variables that have meaning in the OPA ruleset:

- `TFLINT_OPA_POLICY_DIR`
- Directory where policy files are placed. See [Configuration](./configuration.md).
- `TFLINT_OPA_POLICY_DIRS`
- Directories where policy files are placed. Supports multiple directories separated by `,`. See [Configuration](./configuration.md).
- `TFLINT_OPA_TRACE`
- Enable tracing. See [Debugging](./debug.md).
- `TFLINT_OPA_TEST`
Expand Down
2 changes: 1 addition & 1 deletion integration/checks/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/data_sources/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/ephemerals/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/expr_without_eval/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/imports/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/instance_type/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/locals/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/module_calls/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/moved/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/naming_convention/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/outputs/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/providers/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/removed/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/resources/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/settings/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/tagged/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/variables/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/volume_size/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
2 changes: 1 addition & 1 deletion integration/volume_type/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ plugin "terraform" {
plugin "opa" {
enabled = true

policy_dir = "policies"
policy_dirs = ["policies"]
}
49 changes: 38 additions & 11 deletions opa/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,72 @@ package opa

import (
"os"
"strings"

"github.com/mitchellh/go-homedir"
)

// Config is the configuration for the ruleset.
type Config struct {
PolicyDir string `hclext:"policy_dir,optional"`
PolicyDirs []string `hclext:"policy_dirs,optional"`
}

var (
policyRoot = "~/.tflint.d/policies"
localPolicyRoot = "./.tflint.d/policies"
)

// policyDir returns the base policy directory.
// policyDirs returns the policy directories to load.
// Adopted with the following priorities:
//
// 1. `policy_dir` in a config file
// 2. `TFLINT_OPA_POLICY_DIR` environment variable
// 1. `policy_dirs` in a config file
// 2. `TFLINT_OPA_POLICY_DIRS` environment variable (supports multiple directories separated by `,`)
// 3. Current directory (./.tflint.d/policies)
// 4. Home directory (~/.tflint.d/policies)
//
// If the environment variable is set, other directories will not be considered,
// but if the current directory does not exist, it will fallback to the home directory.
func (c *Config) policyDir() (string, error) {
if c.PolicyDir != "" {
return homedir.Expand(c.PolicyDir)
func (c *Config) policyDirs() ([]string, error) {
var expandedDirs []string

// Priority 1: policy_dirs from config
for _, dir := range c.PolicyDirs {
expanded, err := homedir.Expand(dir)
if err != nil {
return nil, err
}
expandedDirs = append(expandedDirs, expanded)
}

if len(expandedDirs) > 0 {
return expandedDirs, nil
}

// Priority 2: TFLINT_OPA_POLICY_DIRS environment variable
// Supports multiple directories separated by `,`
for dir := range strings.SplitSeq(os.Getenv("TFLINT_OPA_POLICY_DIRS"), ",") {
dir = strings.TrimSpace(dir)
if dir != "" {
expanded, err := homedir.Expand(dir)
if err != nil {
return nil, err
}
expandedDirs = append(expandedDirs, expanded)
}
}

if dir := os.Getenv("TFLINT_OPA_POLICY_DIR"); dir != "" {
return dir, nil
if len(expandedDirs) > 0 {
return expandedDirs, nil
}

// Priority 3 & 4: Check local directory, fallback to home directory
_, err := os.Stat(localPolicyRoot)
if os.IsNotExist(err) {
return policyRootDir()
dir, err := policyRootDir()
return []string{dir}, err
}

return localPolicyRoot, err
return []string{localPolicyRoot}, err
}

func policyRootDir() (string, error) {
Expand Down
64 changes: 52 additions & 12 deletions opa/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,40 +19,74 @@ func TestPolicyDir(t *testing.T) {
root string
currentDir string
env map[string]string
want string
want []string
err error
}{
{
name: "default (not exists)",
config: &Config{},
root: filepath.Join(cwd, "test-fixtures", "config", "root-not-exists", ".tflint.d", "policies"),
want: filepath.Join(cwd, "test-fixtures", "config", "root-not-exists", ".tflint.d", "policies"),
want: []string{filepath.Join(cwd, "test-fixtures", "config", "root-not-exists", ".tflint.d", "policies")},
err: os.ErrNotExist,
},
{
name: "default (exists)",
config: &Config{},
root: filepath.Join(cwd, "test-fixtures", "config", "root-exists", ".tflint.d", "policies"),
want: filepath.Join(cwd, "test-fixtures", "config", "root-exists", ".tflint.d", "policies"),
want: []string{filepath.Join(cwd, "test-fixtures", "config", "root-exists", ".tflint.d", "policies")},
},
{
name: "local",
config: &Config{},
currentDir: filepath.Join(cwd, "test-fixtures", "config", "local"),
want: "./.tflint.d/policies",
want: []string{"./.tflint.d/policies"},
},
{
name: "env",
config: &Config{},
env: map[string]string{
"TFLINT_OPA_POLICY_DIR": "policies",
"TFLINT_OPA_POLICY_DIRS": "policies",
},
want: "policies",
want: []string{"policies"},
},
{
name: "config",
config: &Config{PolicyDir: "config/policies"},
want: "config/policies",
name: "env multiple directories",
config: &Config{},
env: map[string]string{
"TFLINT_OPA_POLICY_DIRS": "policies,other/policies",
},
want: []string{"policies", "other/policies"},
},
{
name: "env multiple directories with spaces",
config: &Config{},
env: map[string]string{
"TFLINT_OPA_POLICY_DIRS": " policies , other/policies ",
},
want: []string{"policies", "other/policies"},
},
{
name: "env with tilde expansion",
config: &Config{},
env: map[string]string{
"TFLINT_OPA_POLICY_DIRS": "~/policies",
},
want: []string{filepath.Join(os.Getenv("HOME"), "policies")},
},
{
name: "config single directory",
config: &Config{PolicyDirs: []string{"config/policies"}},
want: []string{"config/policies"},
},
{
name: "config multiple directories",
config: &Config{PolicyDirs: []string{"config/policies", "other/policies"}},
want: []string{"config/policies", "other/policies"},
},
{
name: "config with tilde expansion",
config: &Config{PolicyDirs: []string{"~/policies"}},
want: []string{filepath.Join(os.Getenv("HOME"), "policies")},
},
}

Expand All @@ -71,7 +105,7 @@ func TestPolicyDir(t *testing.T) {
t.Setenv(k, v)
}

got, err := test.config.policyDir()
got, err := test.config.policyDirs()
if err != nil {
if errors.Is(err, test.err) {
return
Expand All @@ -82,8 +116,14 @@ func TestPolicyDir(t *testing.T) {
t.Fatal("should return an error, but it does not")
}

if got != test.want {
t.Fatalf("want: %s, got: %s", test.want, got)
if len(got) != len(test.want) {
t.Fatalf("want: %v, got: %v", test.want, got)
}

for i := range got {
if got[i] != test.want[i] {
t.Fatalf("want: %v, got: %v", test.want, got)
}
}
})
}
Expand Down
Loading