Skip to content

Commit

Permalink
feat: prevent planning and applying directories outside PR scope usin…
Browse files Browse the repository at this point in the history
…g `--restrict-file-list` (#2440)

* Add --strict-plan-file-list config

* Update server.go

* Update server-configuration.md

* Update server_test.go

* Run gofmt -w

* Add --strict-plan-file-list for projects

* Add --strict-plan-file-list tests

* Change --strict-plan-file-list to --restrict-file-list

* Update --restrict-file-list documentation

* Update --restrict-file-list and --enable-regexp-cmd documentation

Co-authored-by: Fabiano Honorato <[email protected]>
Co-authored-by: nitrocode <[email protected]>
Co-authored-by: PePe Amengual <[email protected]>
  • Loading branch information
4 people authored Dec 9, 2022
1 parent c800f70 commit 66dc30e
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 10 deletions.
5 changes: 5 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ const (
SlackTokenFlag = "slack-token"
SSLCertFileFlag = "ssl-cert-file"
SSLKeyFileFlag = "ssl-key-file"
RestrictFileList = "restrict-file-list"
TFDownloadURLFlag = "tf-download-url"
VarFileAllowlistFlag = "var-file-allowlist"
VCSStatusName = "vcs-status-name"
Expand Down Expand Up @@ -496,6 +497,10 @@ var boolFlags = map[string]boolFlag{
description: "Switches on or off the Basic Authentication on the HTTP Middleware interface",
defaultValue: DefaultWebBasicAuth,
},
RestrictFileList: {
description: "Block plan requests from projects outside the files modified in the pull request.",
defaultValue: false,
},
WebsocketCheckOrigin: {
description: "Enable websocket origin check",
defaultValue: false,
Expand Down
1 change: 1 addition & 0 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ var testFlags = map[string]interface{}{
SlackTokenFlag: "slack-token",
SSLCertFileFlag: "cert-file",
SSLKeyFileFlag: "key-file",
RestrictFileList: false,
TFDownloadURLFlag: "https://my-hostname.com",
TFEHostnameFlag: "my-hostname",
TFELocalExecutionModeFlag: true,
Expand Down
13 changes: 13 additions & 0 deletions runatlantis.io/docs/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ and set `--autoplan-modules` to `false`.

This will not work with `-d` yet and to use `-p` the repo projects must be defined in the repo `atlantis.yaml` file.

This will bypass `--restrict-file-list` if regex is used, normal commands will stil be blocked if necessary.

::: warning SECURITY WARNING
It's not supposed to be used with `--disable-apply-all`.
The command `atlantis apply -p .*` will bypass the restriction and run apply on every projects.
Expand Down Expand Up @@ -886,6 +888,17 @@ and set `--autoplan-modules` to `false`.
```
File containing x509 private key matching `--ssl-cert-file`.

### `--restrict-file-list`
```bash
atlantis server --restrict-file-list
# or (recommended)
ATLANTIS_RESTRICT_FILE_LIST=true
```
`--restrict-file-list` will block plan requests from projects outside the files modified in the pull request.
This will not block plan requests with regex if using the `--enable-regexp-cmd` flag, in these cases commands
like `atlantis plan -p .*` will still work if used. normal commands will stil be blocked if necessary.
Defaults to `false`.

### `--stats-namespace`
```bash
atlantis server --stats-namespace="myatlantis"
Expand Down
1 change: 1 addition & 0 deletions server/controllers/events/events_controller_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,7 @@ func setupE2E(t *testing.T, repoDir string) (events_controllers.VCSEventsControl
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
statsScope,
logger,
)
Expand Down
72 changes: 65 additions & 7 deletions server/events/project_command_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package events
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"

"github.com/uber-go/tally"

Expand Down Expand Up @@ -48,6 +50,7 @@ func NewInstrumentedProjectCommandBuilder(
EnableRegExpCmd bool,
AutoDetectModuleFiles string,
AutoplanFileList string,
RestrictFileList bool,
scope tally.Scope,
logger logging.SimpleLogging,
) *InstrumentedProjectCommandBuilder {
Expand All @@ -66,6 +69,7 @@ func NewInstrumentedProjectCommandBuilder(
EnableRegExpCmd,
AutoDetectModuleFiles,
AutoplanFileList,
RestrictFileList,
scope,
logger,
),
Expand All @@ -87,6 +91,7 @@ func NewProjectCommandBuilder(
EnableRegExpCmd bool,
AutoDetectModuleFiles string,
AutoplanFileList string,
RestrictFileList bool,
scope tally.Scope,
logger logging.SimpleLogging,
) *DefaultProjectCommandBuilder {
Expand All @@ -102,6 +107,7 @@ func NewProjectCommandBuilder(
EnableRegExpCmd: EnableRegExpCmd,
AutoDetectModuleFiles: AutoDetectModuleFiles,
AutoplanFileList: AutoplanFileList,
RestrictFileList: RestrictFileList,
ProjectCommandContextBuilder: NewProjectCommandContextBuilder(
policyChecksSupported,
commentBuilder,
Expand Down Expand Up @@ -166,6 +172,7 @@ type DefaultProjectCommandBuilder struct {
AutoDetectModuleFiles string
AutoplanFileList string
EnableDiffMarkdownFormat bool
RestrictFileList bool
}

// See ProjectCommandBuilder.BuildAutoplanCommands.
Expand Down Expand Up @@ -372,6 +379,64 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont
}

var pcc []command.ProjectContext

// use the default repository workspace because it is the only one guaranteed to have an atlantis.yaml,
// other workspaces will not have the file if they are using pre_workflow_hooks to generate it dynamically
defaultRepoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, DefaultWorkspace)
if err != nil {
return pcc, err
}

if p.RestrictFileList {
modifiedFiles, err := p.VCSClient.GetModifiedFiles(ctx.Pull.BaseRepo, ctx.Pull)
if err != nil {
return nil, err
}

if cmd.RepoRelDir != "" {
foundDir := false

for _, f := range modifiedFiles {
if filepath.Dir(f) == cmd.RepoRelDir {
foundDir = true
}
}

if !foundDir {
return pcc, fmt.Errorf("the dir \"%s\" is not in the plan list of this pull request", cmd.RepoRelDir)
}
}

if cmd.ProjectName != "" {
var notFoundFiles = []string{}
var repoConfig valid.RepoCfg

repoConfig, err = p.ParserValidator.ParseRepoCfg(defaultRepoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch)
if err != nil {
return pcc, err
}
repoCfgProjects := repoConfig.FindProjectsByName(cmd.ProjectName)

for _, f := range modifiedFiles {
foundDir := false

for _, p := range repoCfgProjects {
if filepath.Dir(f) == p.Dir {
foundDir = true
}
}

if !foundDir {
notFoundFiles = append(notFoundFiles, filepath.Dir(f))
}
}

if len(notFoundFiles) > 0 {
return pcc, fmt.Errorf("the following directories are present in the pull request but not in the requested project:\n%s", strings.Join(notFoundFiles, "\n"))
}
}
}

ctx.Log.Debug("building plan command")
unlockFn, err := p.WorkingDirLocker.TryLock(ctx.Pull.BaseRepo.FullName, ctx.Pull.Num, workspace, DefaultRepoRelDir)
if err != nil {
Expand All @@ -390,13 +455,6 @@ func (p *DefaultProjectCommandBuilder) buildProjectPlanCommand(ctx *command.Cont
repoRelDir = cmd.RepoRelDir
}

// use the default repository workspace because it is the only one guaranteed to have an atlantis.yaml,
// other workspaces will not have the file if they are using pre_workflow_hooks to generate it dynamically
defaultRepoDir, err := p.WorkingDir.GetWorkingDir(ctx.Pull.BaseRepo, ctx.Pull, DefaultWorkspace)
if err != nil {
return pcc, err
}

return p.buildProjectCommandCtx(
ctx,
command.Plan,
Expand Down
3 changes: 3 additions & 0 deletions server/events/project_command_builder_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ projects:
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
statsScope,
logger,
)
Expand Down Expand Up @@ -829,6 +830,7 @@ projects:
true,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
statsScope,
logger,
)
Expand Down Expand Up @@ -1059,6 +1061,7 @@ workflows:
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
false,
statsScope,
logger,
)
Expand Down
Loading

0 comments on commit 66dc30e

Please sign in to comment.