Skip to content

Commit

Permalink
feat: adds allowed_regexp_prefixes parameter to use with the `--ena…
Browse files Browse the repository at this point in the history
…ble-regexp-cmd` flag (#1884)

* adds AllowedRegexpPrefixes config and use it on the FindProjectsByName method

* adds tests for the new AllowedRegexpPrefixes config

* update documentation with the new AllowedRegexpPrefixes config
  • Loading branch information
bmbferreira authored Nov 17, 2021
1 parent dc4cc2f commit 79af924
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 6 deletions.
5 changes: 5 additions & 0 deletions runatlantis.io/docs/repo-level-atlantis-yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ workflows:
steps:
- run: echo hi
- apply
allowed_regexp_prefixes:
- dev/
- staging/
```
## Use Cases
Expand Down Expand Up @@ -194,6 +197,7 @@ automerge:
delete_source_branch_on_merge:
projects:
workflows:
allowed_regexp_prefixes:
```
| Key | Type | Default | Required | Description |
|-------------------------------|----------------------------------------------------------|---------|----------|-------------------------------------------------------------|
Expand All @@ -202,6 +206,7 @@ workflows:
| delete_source_branch_on_merge | bool | `false` | no | Automatically deletes the source branch on merge |
| projects | array[[Project](repo-level-atlantis-yaml.html#project)] | `[]` | no | Lists the projects in this repo |
| workflows<br />*(restricted)* | map[string: [Workflow](custom-workflows.html#reference)] | `{}` | no | Custom workflows |
| allowed_regexp_prefixes | array[string] | `[]` | no | Lists the allowed regexp prefixes to use when the [`--enable-regexp-cmd`](server-configuration.html#enable-regexp-cmd) flag is used

### Project
```yaml
Expand Down
2 changes: 2 additions & 0 deletions server/events/yaml/raw/repo_cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type RepoCfg struct {
ParallelApply *bool `yaml:"parallel_apply,omitempty"`
ParallelPlan *bool `yaml:"parallel_plan,omitempty"`
DeleteSourceBranchOnMerge *bool `yaml:"delete_source_branch_on_merge,omitempty"`
AllowedRegexpPrefixes []string `yaml:"allowed_regexp_prefixes,omitempty"`
}

func (r RepoCfg) Validate() error {
Expand Down Expand Up @@ -87,5 +88,6 @@ func (r RepoCfg) ToValid() valid.RepoCfg {
ParallelPlan: parallelPlan,
ParallelPolicyCheck: parallelPlan,
DeleteSourceBranchOnMerge: r.DeleteSourceBranchOnMerge,
AllowedRegexpPrefixes: r.AllowedRegexpPrefixes,
}
}
6 changes: 5 additions & 1 deletion server/events/yaml/raw/repo_cfg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ workflows:
policy_check:
steps: []
apply:
steps: []`,
steps: []
allowed_regexp_prefixes:
- dev/
- staging/`,
exp: raw.RepoCfg{
Version: Int(3),
Automerge: Bool(true),
Expand Down Expand Up @@ -176,6 +179,7 @@ workflows:
},
},
},
AllowedRegexpPrefixes: []string{"dev/", "staging/"},
},
},
}
Expand Down
25 changes: 20 additions & 5 deletions server/events/yaml/valid/repo_cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type RepoCfg struct {
ParallelPlan bool
ParallelPolicyCheck bool
DeleteSourceBranchOnMerge *bool
AllowedRegexpPrefixes []string
}

func (r RepoCfg) FindProjectsByDirWorkspace(repoRelDir string, workspace string) []Project {
Expand Down Expand Up @@ -57,17 +58,31 @@ func (r RepoCfg) FindProjectByName(name string) *Project {
// FindProjectsByName returns all projects that match with name.
func (r RepoCfg) FindProjectsByName(name string) []Project {
var ps []Project
sanitizedName := "^" + name + "$"
for _, p := range r.Projects {
if p.Name != nil {
if match, _ := regexp.MatchString(sanitizedName, *p.Name); match {
ps = append(ps, p)
if isRegexAllowed(name, r.AllowedRegexpPrefixes) {
sanitizedName := "^" + name + "$"
for _, p := range r.Projects {
if p.Name != nil {
if match, _ := regexp.MatchString(sanitizedName, *p.Name); match {
ps = append(ps, p)
}
}
}
}
return ps
}

func isRegexAllowed(name string, allowedRegexpPrefixes []string) bool {
if len(allowedRegexpPrefixes) == 0 {
return true
}
for _, allowedRegexPrefix := range allowedRegexpPrefixes {
if strings.HasPrefix(name, allowedRegexPrefix) {
return true
}
}
return false
}

// validateWorkspaceAllowed returns an error if repoCfg defines projects in
// repoRelDir but none of them use workspace. We want this to be an error
// because if users have gone to the trouble of defining projects in repoRelDir
Expand Down
175 changes: 175 additions & 0 deletions server/events/yaml/valid/repo_cfg_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package valid_test

import (
"testing"

validation "github.com/go-ozzo/ozzo-validation"
version "github.com/hashicorp/go-version"
"github.com/runatlantis/atlantis/server/events/yaml/valid"
. "github.com/runatlantis/atlantis/testing"
)

func TestConfig_FindProjectsByDir(t *testing.T) {
tfVersion, _ := version.NewVersion("v0.11.0")
cases := []struct {
description string
nameRegex string
input valid.RepoCfg
expProjects []valid.Project
}{
{
description: "Find projects with 'dev' prefix as allowed prefix",
nameRegex: "dev.*",
input: valid.RepoCfg{
Version: 3,
Projects: []valid.Project{
{
Dir: ".",
Name: String("dev_terragrunt_myproject"),
Workspace: "myworkspace",
TerraformVersion: tfVersion,
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"},
Enabled: false,
},
ApplyRequirements: []string{"approved"},
},
},
Workflows: map[string]valid.Workflow{
"myworkflow": {
Name: "myworkflow",
Apply: valid.DefaultApplyStage,
Plan: valid.DefaultPlanStage,
PolicyCheck: valid.DefaultPolicyCheckStage,
},
},
AllowedRegexpPrefixes: []string{"dev", "staging"},
},
expProjects: []valid.Project{
{
Dir: ".",
Name: String("dev_terragrunt_myproject"),
Workspace: "myworkspace",
TerraformVersion: tfVersion,
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"},
Enabled: false,
},
ApplyRequirements: []string{"approved"},
},
},
},
{
description: "Only find projects with allowed prefix",
nameRegex: ".*",
input: valid.RepoCfg{
Version: 3,
Projects: []valid.Project{
{
Dir: ".",
Name: String("dev_terragrunt_myproject"),
Workspace: "myworkspace",
TerraformVersion: tfVersion,
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"},
Enabled: false,
},
ApplyRequirements: []string{"approved"},
},
{
Dir: ".",
Name: String("staging_terragrunt_myproject"),
Workspace: "myworkspace",
TerraformVersion: tfVersion,
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"},
Enabled: false,
},
ApplyRequirements: []string{"approved"},
},
},
Workflows: map[string]valid.Workflow{
"myworkflow": {
Name: "myworkflow",
Apply: valid.DefaultApplyStage,
Plan: valid.DefaultPlanStage,
PolicyCheck: valid.DefaultPolicyCheckStage,
},
},
AllowedRegexpPrefixes: []string{"dev", "staging"},
},
expProjects: nil,
},
{
description: "Find all projects without restrictions of allowed prefix",
nameRegex: ".*",
input: valid.RepoCfg{
Version: 3,
Projects: []valid.Project{
{
Dir: ".",
Name: String("dev_terragrunt_myproject"),
Workspace: "myworkspace",
TerraformVersion: tfVersion,
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"},
Enabled: false,
},
ApplyRequirements: []string{"approved"},
},
{
Dir: ".",
Name: String("staging_terragrunt_myproject"),
Workspace: "myworkspace",
TerraformVersion: tfVersion,
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"},
Enabled: false,
},
ApplyRequirements: []string{"approved"},
},
},
Workflows: map[string]valid.Workflow{
"myworkflow": {
Name: "myworkflow",
Apply: valid.DefaultApplyStage,
Plan: valid.DefaultPlanStage,
PolicyCheck: valid.DefaultPolicyCheckStage,
},
},
AllowedRegexpPrefixes: nil,
},
expProjects: []valid.Project{
{
Dir: ".",
Name: String("dev_terragrunt_myproject"),
Workspace: "myworkspace",
TerraformVersion: tfVersion,
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"},
Enabled: false,
},
ApplyRequirements: []string{"approved"},
},
{
Dir: ".",
Name: String("staging_terragrunt_myproject"),
Workspace: "myworkspace",
TerraformVersion: tfVersion,
Autoplan: valid.Autoplan{
WhenModified: []string{"**/*.tf*", "**/terragrunt.hcl"},
Enabled: false,
},
ApplyRequirements: []string{"approved"},
},
},
},
}
validation.ErrorTag = "yaml"
for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
projects := c.input.FindProjectsByName(c.nameRegex)
Equals(t, c.expProjects, projects)
})
}
}

0 comments on commit 79af924

Please sign in to comment.