Skip to content

Commit

Permalink
Added new --allow-restricted-repo-config and --repo-config options
Browse files Browse the repository at this point in the history
This allows usage of a server side repo config file to restrict
certain fields from being used in a repos atlantis.yaml file.

When this feature is activated apply_requirements, workflow,
and workflows can only be specified in an atlantis.yaml file
if explicitly allowed by the server side repo config.

The repo config file provides the ability to specify a default set of
workflows, and default values for apply_requirements and workflow to use
use on a per repo basis.  It also supports applying to a collection of
repos by using regex to match a repo name.

If more than one repo name matches, the values from last repo matched
are used.
  • Loading branch information
jjulien committed Feb 28, 2019
1 parent 7bf5f07 commit 0588a06
Show file tree
Hide file tree
Showing 17 changed files with 1,101 additions and 122 deletions.
85 changes: 56 additions & 29 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,35 +36,37 @@ import (
// 3. Add your flag's description etc. to the stringFlags, intFlags, or boolFlags slices.
const (
// Flag names.
AllowForkPRsFlag = "allow-fork-prs"
AllowRepoConfigFlag = "allow-repo-config"
AtlantisURLFlag = "atlantis-url"
AutomergeFlag = "automerge"
BitbucketBaseURLFlag = "bitbucket-base-url"
BitbucketTokenFlag = "bitbucket-token"
BitbucketUserFlag = "bitbucket-user"
BitbucketWebhookSecretFlag = "bitbucket-webhook-secret"
ConfigFlag = "config"
CheckoutStrategyFlag = "checkout-strategy"
DataDirFlag = "data-dir"
GHHostnameFlag = "gh-hostname"
GHTokenFlag = "gh-token"
GHUserFlag = "gh-user"
GHWebhookSecretFlag = "gh-webhook-secret" // nolint: gosec
GitlabHostnameFlag = "gitlab-hostname"
GitlabTokenFlag = "gitlab-token"
GitlabUserFlag = "gitlab-user"
GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec
LogLevelFlag = "log-level"
PortFlag = "port"
RepoWhitelistFlag = "repo-whitelist"
RequireApprovalFlag = "require-approval"
RequireMergeableFlag = "require-mergeable"
SilenceWhitelistErrorsFlag = "silence-whitelist-errors"
SlackTokenFlag = "slack-token"
SSLCertFileFlag = "ssl-cert-file"
SSLKeyFileFlag = "ssl-key-file"
TFETokenFlag = "tfe-token"
AllowForkPRsFlag = "allow-fork-prs"
AllowRepoConfigFlag = "allow-repo-config"
AllowRestrictedRepoConfigFlag = "allow-restricted-repo-config"
AtlantisURLFlag = "atlantis-url"
AutomergeFlag = "automerge"
BitbucketBaseURLFlag = "bitbucket-base-url"
BitbucketTokenFlag = "bitbucket-token"
BitbucketUserFlag = "bitbucket-user"
BitbucketWebhookSecretFlag = "bitbucket-webhook-secret"
ConfigFlag = "config"
CheckoutStrategyFlag = "checkout-strategy"
DataDirFlag = "data-dir"
GHHostnameFlag = "gh-hostname"
GHTokenFlag = "gh-token"
GHUserFlag = "gh-user"
GHWebhookSecretFlag = "gh-webhook-secret" // nolint: gosec
GitlabHostnameFlag = "gitlab-hostname"
GitlabTokenFlag = "gitlab-token"
GitlabUserFlag = "gitlab-user"
GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec
LogLevelFlag = "log-level"
PortFlag = "port"
RepoConfigFlag = "repo-config"
RepoWhitelistFlag = "repo-whitelist"
RequireApprovalFlag = "require-approval"
RequireMergeableFlag = "require-mergeable"
SilenceWhitelistErrorsFlag = "silence-whitelist-errors"
SlackTokenFlag = "slack-token"
SSLCertFileFlag = "ssl-cert-file"
SSLKeyFileFlag = "ssl-key-file"
TFETokenFlag = "tfe-token"

// Flag defaults.
DefaultCheckoutStrategy = "branch"
Expand Down Expand Up @@ -167,6 +169,10 @@ var stringFlags = []stringFlag{
description: "Log level. Either debug, info, warn, or error.",
defaultValue: DefaultLogLevel,
},
{
name: RepoConfigFlag,
description: "Path to a repo config file, used to configure how atlantis.yaml will behave on repos. Repos can be specified as an exact string or using regular expressions",
},
{
name: RepoWhitelistFlag,
description: "Comma separated list of repositories that Atlantis will operate on. " +
Expand Down Expand Up @@ -205,6 +211,12 @@ var boolFlags = []boolFlag{
" Should only be enabled in a trusted environment since it enables a pull request to run arbitrary commands" +
" on the Atlantis server.",
defaultValue: false,
deprecated: fmt.Sprintf("use --%s instead", AllowRestrictedRepoConfigFlag),
},
{
name: AllowRestrictedRepoConfigFlag,
description: fmt.Sprintf("Restrict sensitive fields in atlantis.yaml and use config file provided by --%s to define how atlantis should act on repositories.", RepoConfigFlag),
defaultValue: false,
},
{
name: AutomergeFlag,
Expand Down Expand Up @@ -239,16 +251,19 @@ type stringFlag struct {
name string
description string
defaultValue string
deprecated string
}
type intFlag struct {
name string
description string
defaultValue int
deprecated string
}
type boolFlag struct {
name string
description string
defaultValue bool
deprecated string
}

// ServerCmd is an abstraction that helps us test. It allows
Expand Down Expand Up @@ -324,6 +339,9 @@ func (s *ServerCmd) Init() *cobra.Command {
usage = fmt.Sprintf("%s (default \"%s\")", usage, f.defaultValue)
}
c.Flags().String(f.name, "", usage+"\n")
if f.deprecated != "" {
c.Flags().MarkDeprecated(f.name, f.deprecated) // nolint: errcheck
}
s.Viper.BindPFlag(f.name, c.Flags().Lookup(f.name)) // nolint: errcheck
}

Expand All @@ -334,12 +352,18 @@ func (s *ServerCmd) Init() *cobra.Command {
usage = fmt.Sprintf("%s (default %d)", usage, f.defaultValue)
}
c.Flags().Int(f.name, 0, usage+"\n")
if f.deprecated != "" {
c.Flags().MarkDeprecated(f.name, f.deprecated) // nolint: errcheck
}
s.Viper.BindPFlag(f.name, c.Flags().Lookup(f.name)) // nolint: errcheck
}

// Set bool flags.
for _, f := range boolFlags {
c.Flags().Bool(f.name, f.defaultValue, f.description+"\n")
if f.deprecated != "" {
c.Flags().MarkDeprecated(f.name, f.deprecated) // nolint: errcheck
}
s.Viper.BindPFlag(f.name, c.Flags().Lookup(f.name)) // nolint: errcheck
}

Expand Down Expand Up @@ -431,6 +455,9 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error {
if (userConfig.SSLKeyFile == "") != (userConfig.SSLCertFile == "") {
return fmt.Errorf("--%s and --%s are both required for ssl", SSLKeyFileFlag, SSLCertFileFlag)
}
if userConfig.AllowRepoConfig && userConfig.AllowRestrictedRepoConfig {
return fmt.Errorf("You cannot use both --%s and --%s together. --%s is deprecated and will be removed in a later version, you should use --%s instead", AllowRepoConfigFlag, AllowRestrictedRepoConfigFlag, AllowRepoConfigFlag, AllowRestrictedRepoConfigFlag)
}

// The following combinations are valid.
// 1. github user and token set
Expand Down
10 changes: 10 additions & 0 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,16 @@ func TestExecute_BitbucketServerBaseURLPort(t *testing.T) {
Equals(t, "http://mydomain.com:7990", passedConfig.BitbucketBaseURL)
}

// Cannot use both allow-repo-config and allow-restricted-repo-config together
func TestExecute_AllowRepoConfigWithAllowRestrictedRepoConfig(t *testing.T) {
c := setup(map[string]interface{}{
cmd.AllowRepoConfigFlag: true,
cmd.AllowRestrictedRepoConfigFlag: true,
})
err := c.Execute()
ErrEquals(t, "You cannot use both --allow-repo-config and --allow-restricted-repo-config together. --allow-repo-config is deprecated and will be removed in a later version, you should use --allow-restricted-repo-config instead", err)
}

func setup(flags map[string]interface{}) *cobra.Command {
vipr := viper.New()
for k, v := range flags {
Expand Down
1 change: 1 addition & 0 deletions runatlantis.io/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ module.exports = {
collapsable: true,
children: [
['customizing-atlantis', 'Overview'],
'repos-yaml-reference',
'atlantis-yaml-reference',
'upgrading-atlantis-yaml-to-version-2',
'apply-requirements'
Expand Down
74 changes: 66 additions & 8 deletions runatlantis.io/docs/apply-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,21 @@ by at least one person other than the author.
#### Usage
You can set the `approved` requirement by:
1. Passing the `--require-approval` flag to `atlantis server` or
1. Creating an `atlantis.yaml` file with the `apply_requirements` key:
1. Creating a `repos.yaml` file with the `apply_requirements` key:
```yaml
repos:
- id: /.*/
apply_requirements: [approved]
```
1. Or by allowing an `atlantis.yaml` file to specify the `apply_requirements` key in your `repos.yaml` config:
#### repos.yaml
```yaml
repos:
- id: /.*/
allowed_overrides: [apply_requirements]
```

#### atlantis.yaml
```yaml
version: 2
projects:
Expand All @@ -47,14 +61,29 @@ The `mergeable` requirement will prevent applies unless a pull request is able t
#### Usage
You can set the `mergeable` requirement by:
1. Passing the `--require-mergeable` flag to `atlantis server` or
1. Creating an `atlantis.yaml` file with the `apply_requirements` key:
1. Creating a `repos.yaml` file with the `apply_requirements` key:
```yaml
repos:
- id: /.*/
apply_requirements: [mergeable]
```

1. Or by allowing an `atlantis.yaml` file to specify the `apply_requirements` key in your `repos.yaml` config:
#### repos.yaml
```yaml
repos:
- id: /.*/
allowed_overrides: [apply_requirements]
```

#### atlantis.yaml
```yaml
version: 2
projects:
- dir: .
apply_requirements: [mergeable]
```

```
#### Meaning
Each VCS provider has a different concept of "mergeability":
#### GitHub
Expand Down Expand Up @@ -86,18 +115,47 @@ If you need a specific check, please
[open an issue](https://github.com/runatlantis/atlantis/issues/new).

## Setting Apply Requirements
As mentioned above, you can set apply requirements via flags or `atlantis.yaml`.
As mentioned above, you can set apply requirements via flags, in `repos.yaml`, or in `atlantis.yaml` if `repos.yaml`
allows the override.

### Flags Override
Flags **override** any `atlantis.yaml` settings so they are equivalent to always
Flags **override** any `repos.yaml` or `atlantis.yaml` settings so they are equivalent to always
having that apply requirement set.

### Project-Specific Settings
If you only want some projects/repos to have apply requirements, then you must
1. Not set the `--require-approval` or `--require-mergeable` flags, since those
will override any `atlantis.yaml` settings
1. Specify which projects have which requirements via an `atlantis.yaml` file.
will override any `repos.yaml` or `atlantis.yaml` settings
1. Specifying which repos have which requirements via the `repos.yaml` file.
```yaml
repos:
- id: /.*/
apply_requirements: [approved]
# Regex that defaults all repos to requiring approval
- id: /github.com/runatlantis/.*/
# Regex to match any repo under the atlantis namespace, and not require approval
# except for repos that might match later in the chain
apply_requirements: []
- id: github.com/runatlantis/atlantis
apply_requirements: [approved]
# Exact string match of the github.com/runatlantis/atlantis repo
# that sets apply_requirements to approved
```

1. Specify which projects have which requirements via an `atlantis.yaml` file, and allowing
`apply_requirements` to be set in in `atlantis.yaml` by the server side `repos.yaml`
config.

For example if I have two directories, `staging` and `production`, I might use:
#### repos.yaml
```yaml
repos:
- id: /.*/
allowed_overrides: [apply_requirements]
# Allow any repo to specify apply_requirements in atlantis.yaml
```

#### atlatis.yaml
```yaml
version: 2
projects:
Expand Down
Loading

0 comments on commit 0588a06

Please sign in to comment.