Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add option allowing usage of custom policy check tools #3765

Merged
merged 4 commits into from
Oct 6, 2023
Merged
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
45 changes: 45 additions & 0 deletions runatlantis.io/docs/custom-policy-checks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Custom Policy Checks
If you want to run custom policy tools or scripts instead of the built-in Conftest integration, you can do so by setting the `custom_policy_check` option and running it in a custom workflow. Note: custom policy tool output is simply parsed for "fail" substrings to determine if the policy set passed.

This option can be configured either at the server-level in a [repos.yaml config file](server-configuration.md) or at the repo-level in an [atlantis.yaml file.](repo-level-atlantis-yaml.md).

## Server-side config example
Set the `policy_check` and `custom_policy_check` options to true, and run the custom tool in the policy check steps as seen below. No

```yaml
repos:
- id: /.*/
branch: /^main$/
apply_requirements: [mergeable, undiverged, approved]
policy_check: true
custom_policy_check: true
workflow: custom
workflows:
custom:
policy_check:
steps:
- show
- run: cnspec scan terraform plan $SHOWFILE --policy-bundle example-cnspec-policies.mql.yaml
policies:
owners:
users:
- example_ghuser
policy_sets:
- name: example-set
path: example-cnspec-policies.mql.yaml
source: local
```


## Repo-level atlantis.yaml example
First, you will need to ensure `custom_policy_check` is within the `allowed_overrides` field of the server-side config. Next, just set the custom option to true on the specific project you want as shown in the example `atlantis.yaml` below:

```yaml
version: 3
projects:
- name: example
dir: ./example
custom_policy_check: true
autoplan:
when_modified: ["*.tf"]
```
2 changes: 1 addition & 1 deletion runatlantis.io/docs/policy-checking.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ When the policy check workflow runs, a file is created in the working directory
[
{
"PolicySetName": "policy1",
"ConftestOutput": "",
"PolicyOutput": "",
"Passed": false,
"ReqApprovals": 1,
"CurApprovals": 0
Expand Down
6 changes: 5 additions & 1 deletion runatlantis.io/docs/repo-level-atlantis-yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ projects:
terraform_version: v0.11.0
delete_source_branch_on_merge: true
repo_locking: true
custom_policy_check: false
autoplan:
when_modified: ["*.tf", "../modules/**/*.tf", ".terraform.lock.hcl"]
enabled: true
Expand Down Expand Up @@ -311,6 +312,7 @@ workspace: myworkspace
execution_order_group: 0
delete_source_branch_on_merge: false
repo_locking: true
custom_policy_check: false
autoplan:
terraform_version: 0.11.0
plan_requirements: ["approved"]
Expand All @@ -327,7 +329,9 @@ workflow: myworkflow
| workspace | string | `"default"` | no | The [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces) for this project. Atlantis will switch to this workplace when planning/applying and will create it if it doesn't exist. |
| execution_order_group | int | `0` | no | Index of execution order group. Projects will be sort by this field before planning/applying. |
| delete_source_branch_on_merge | bool | `false` | no | Automatically deletes the source branch on merge. |
| repo_locking | bool | `true` | no | Get a repository lock in this project when plan. |
| repo_locking | bool | `true` | no | Get a repository lock in this project when plan.

| custom_policy_check | bool | `false` | no | Enable using policy check tools other than Conftest |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add an example on how to use this with another tool?

Copy link
Contributor Author

@bgalkows bgalkows Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jamengual Added custom-policy-checks.md with examples for both ways to set the flag and linked to it from server-side-repo-config.md

| autoplan | [Autoplan](#autoplan) | none | no | A custom autoplan configuration. If not specified, will use the autoplan config. See [Autoplanning](autoplanning.html). |
| terraform_version | string | none | no | A specific Terraform version to use when running commands for this project. Must be [Semver compatible](https://semver.org/), ex. `v0.11.0`, `0.12.0-beta1`. |
| plan_requirements<br />*(restricted)* | array[string] | none | no | Requirements that must be satisfied before `atlantis plan` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.html) for more details. |
Expand Down
12 changes: 10 additions & 2 deletions runatlantis.io/docs/server-side-repo-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ repos:

# allowed_overrides specifies which keys can be overridden by this repo in
# its atlantis.yaml file.
allowed_overrides: [apply_requirements, workflow, delete_source_branch_on_merge, repo_locking]
allowed_overrides: [apply_requirements, workflow, delete_source_branch_on_merge, repo_locking, custom_policy_check]

# allowed_workflows specifies which workflows the repos that match
# are allowed to select.
Expand All @@ -73,6 +73,10 @@ repos:
# If true (default), atlantis try to get a lock.
repo_locking: true

# custom_policy_check defines whether policy checking tools besides Conftest are enabled in checks
# If false (default), only Conftest JSON output is allowed
custom_policy_check: false

# pre_workflow_hooks defines arbitrary list of scripts to execute before workflow execution.
pre_workflow_hooks:
- run: my-pre-workflow-hook-command arg1
Expand Down Expand Up @@ -340,6 +344,9 @@ unless you've created your own server-side workflow with that key (overriding it
See [Custom Workflows](custom-workflows.html) for more details on writing
custom workflows.

### Allow Using Custom Policy Tools
Conftest is the standard policy check application integrated with Atlantis, but custom tools can still be run in custom workflows when the `custom_policy_check` option is set. See the [Custom Policy Checks page](custom-policy-checks.md) for detailed examples.

### Allow Repos To Define Their Own Workflows
If you want repos to be able to define their own workflows you need to
allow them to override the `workflow` key and set `allow_custom_workflows` to `true`.
Expand Down Expand Up @@ -482,12 +489,13 @@ If you set a workflow with the key `default`, it will override this.
| plan_requirements | []string | none | no | Requirements that must be satisfied before `atlantis plan` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.html) for more details. | |
| apply_requirements | []string | none | no | Requirements that must be satisfied before `atlantis apply` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.html) for more details. |
| import_requirements | []string | none | no | Requirements that must be satisfied before `atlantis import` can be run. Currently the only supported requirements are `approved`, `mergeable`, and `undiverged`. See [Command Requirements](command-requirements.html) for more details. |
| allowed_overrides | []string | none | no | A list of restricted keys that `atlantis.yaml` files can override. The only supported keys are `apply_requirements`, `workflow`, `delete_source_branch_on_merge` and `repo_locking` |
| allowed_overrides | []string | none | no | A list of restricted keys that `atlantis.yaml` files can override. The only supported keys are `apply_requirements`, `workflow`, `delete_source_branch_on_merge`,`repo_locking`, and `custom_policy_check` |
| allowed_workflows | []string | none | no | A list of workflows that `atlantis.yaml` files can select from. |
| allow_custom_workflows | bool | false | no | Whether or not to allow [Custom Workflows](custom-workflows.html). |
| delete_source_branch_on_merge | bool | false | no | Whether or not to delete the source branch on merge. |
| repo_locking | bool | false | no | Whether or not to get a lock. |
| policy_check | bool | false | no | Whether or not to run policy checks on this repository. |
| custom_policy_check | bool | false | no | Whether or not to enable custom policy check tools outside of Conftest on this repository. |


:::tip Notes
Expand Down
3 changes: 2 additions & 1 deletion server/core/config/parser_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,7 @@ func TestParseGlobalCfg(t *testing.T) {
input: `repos:
- id: /.*/
allowed_overrides: [invalid]`,
expErr: "repos: (0: (allowed_overrides: \"invalid\" is not a valid override, only \"plan_requirements\", \"apply_requirements\", \"import_requirements\", \"workflow\", \"delete_source_branch_on_merge\", \"repo_locking\" and \"policy_check\" are supported.).).",
expErr: "repos: (0: (allowed_overrides: \"invalid\" is not a valid override, only \"plan_requirements\", \"apply_requirements\", \"import_requirements\", \"workflow\", \"delete_source_branch_on_merge\", \"repo_locking\", \"policy_check\", and \"custom_policy_check\" are supported.).).",
},
"invalid plan_requirement": {
input: `repos:
Expand Down Expand Up @@ -1573,6 +1573,7 @@ workflows:
DeleteSourceBranchOnMerge: Bool(false),
RepoLocking: Bool(true),
PolicyCheck: Bool(false),
CustomPolicyCheck: Bool(false),
},
},
Workflows: map[string]valid.Workflow{
Expand Down
6 changes: 4 additions & 2 deletions server/core/config/raw/global_cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Repo struct {
DeleteSourceBranchOnMerge *bool `yaml:"delete_source_branch_on_merge,omitempty" json:"delete_source_branch_on_merge,omitempty"`
RepoLocking *bool `yaml:"repo_locking,omitempty" json:"repo_locking,omitempty"`
PolicyCheck *bool `yaml:"policy_check,omitempty" json:"policy_check,omitempty"`
CustomPolicyCheck *bool `yaml:"custom_policy_check,omitempty" json:"custom_policy_check,omitempty"`
}

func (g GlobalCfg) Validate() error {
Expand Down Expand Up @@ -192,8 +193,8 @@ func (r Repo) Validate() error {
overridesValid := func(value interface{}) error {
overrides := value.([]string)
for _, o := range overrides {
if o != valid.PlanRequirementsKey && o != valid.ApplyRequirementsKey && o != valid.ImportRequirementsKey && o != valid.WorkflowKey && o != valid.DeleteSourceBranchOnMergeKey && o != valid.RepoLockingKey && o != valid.PolicyCheckKey {
return fmt.Errorf("%q is not a valid override, only %q, %q, %q, %q, %q, %q and %q are supported", o, valid.PlanRequirementsKey, valid.ApplyRequirementsKey, valid.ImportRequirementsKey, valid.WorkflowKey, valid.DeleteSourceBranchOnMergeKey, valid.RepoLockingKey, valid.PolicyCheckKey)
if o != valid.PlanRequirementsKey && o != valid.ApplyRequirementsKey && o != valid.ImportRequirementsKey && o != valid.WorkflowKey && o != valid.DeleteSourceBranchOnMergeKey && o != valid.RepoLockingKey && o != valid.PolicyCheckKey && o != valid.CustomPolicyCheckKey {
return fmt.Errorf("%q is not a valid override, only %q, %q, %q, %q, %q, %q, %q, and %q are supported", o, valid.PlanRequirementsKey, valid.ApplyRequirementsKey, valid.ImportRequirementsKey, valid.WorkflowKey, valid.DeleteSourceBranchOnMergeKey, valid.RepoLockingKey, valid.PolicyCheckKey, valid.CustomPolicyCheckKey)
}
}
return nil
Expand Down Expand Up @@ -331,5 +332,6 @@ OuterGlobalImportReqs:
DeleteSourceBranchOnMerge: r.DeleteSourceBranchOnMerge,
RepoLocking: r.RepoLocking,
PolicyCheck: r.PolicyCheck,
CustomPolicyCheck: r.CustomPolicyCheck,
}
}
5 changes: 5 additions & 0 deletions server/core/config/raw/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Project struct {
RepoLocking *bool `yaml:"repo_locking,omitempty"`
ExecutionOrderGroup *int `yaml:"execution_order_group,omitempty"`
PolicyCheck *bool `yaml:"policy_check,omitempty"`
CustomPolicyCheck *bool `yaml:"custom_policy_check,omitempty"`
}

func (p Project) Validate() error {
Expand Down Expand Up @@ -138,6 +139,10 @@ func (p Project) ToValid() valid.Project {
v.PolicyCheck = p.PolicyCheck
}

if p.CustomPolicyCheck != nil {
v.CustomPolicyCheck = p.CustomPolicyCheck
}

return v
}

Expand Down
Loading