mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-08-05 05:08:50 +00:00
feat: Allow for negations in repo allowlist (#3414)
* feat: Omit repos from allowlist * Add quote in comment * Better comment * Remove test
This commit is contained in:
@@ -46,6 +46,7 @@ For example:
|
||||
* Specific repositories: `--repo-allowlist=github.com/runatlantis/atlantis,github.com/runatlantis/atlantis-tests`
|
||||
* Your whole organization: `--repo-allowlist=github.com/runatlantis/*`
|
||||
* Every repository in your GitHub Enterprise install: `--repo-allowlist=github.yourcompany.com/*`
|
||||
* You can also omit specific repos: `--repo-allowlist='github.com/runatlantis/*,!github.com/runatlantis/untrusted-repo'`
|
||||
* All repositories: `--repo-allowlist=*`. Useful for when you're in a protected network but dangerous without also setting a webhook secret.
|
||||
|
||||
This flag ensures your Atlantis install isn't being used with repositories you don't control. See `atlantis server --help` for more details.
|
||||
|
||||
@@ -810,6 +810,7 @@ This is useful when you have many projects and want to keep the pull request cle
|
||||
* Accepts a comma separated list, ex. `definition1,definition2`
|
||||
* Format is `{hostname}/{owner}/{repo}`, ex. `github.com/runatlantis/atlantis`
|
||||
* `*` matches any characters, ex. `github.com/runatlantis/*` will match all repos in the runatlantis organization
|
||||
* An entry beginning with `!` negates it, ex. `github.com/foo/*,!github.com/foo/bar` will match all github repos in the `foo` owner *except* `bar`.
|
||||
* For Bitbucket Server: `{hostname}` is the domain without scheme and port, `{owner}` is the name of the project (not the key), and `{repo}` is the repo name
|
||||
* User (not project) repositories take on the format: `{hostname}/{full name}/{repo}` (e.g., `bitbucket.example.com/Jane Doe/myatlantis` for username `jdoe` and full name `Jane Doe`, which is not very intuitive)
|
||||
* For Azure DevOps the allowlist takes one of two forms: `{owner}.visualstudio.com/{project}/{repo}` or `dev.azure.com/{owner}/{project}/{repo}`
|
||||
@@ -820,6 +821,8 @@ This is useful when you have many projects and want to keep the pull request cle
|
||||
* `--repo-allowlist=github.com/myorg/repo1,github.com/myorg/repo2`
|
||||
* Allowlist all repos under `myorg` on `github.com`
|
||||
* `--repo-allowlist='github.com/myorg/*'`
|
||||
* Allowlist all repos under `myorg` on `github.com`, excluding `myorg/untrusted-repo`
|
||||
* `--repo-allowlist='github.com/myorg/*,!github.com/myorg/untrusted-repo'`
|
||||
* Allowlist all repos in my GitHub Enterprise installation
|
||||
* `--repo-allowlist='github.yourcompany.com/*'`
|
||||
* Allowlist all repos under `myorg` project `myproject` on Azure DevOps
|
||||
|
||||
@@ -24,20 +24,28 @@ const Wildcard = "*"
|
||||
// RepoAllowlistChecker implements checking if repos are allowlisted to be used with
|
||||
// this Atlantis.
|
||||
type RepoAllowlistChecker struct {
|
||||
rules []string
|
||||
includeRules []string
|
||||
omitRules []string
|
||||
}
|
||||
|
||||
// NewRepoAllowlistChecker constructs a new checker and validates that the
|
||||
// allowlist isn't malformed.
|
||||
func NewRepoAllowlistChecker(allowlist string) (*RepoAllowlistChecker, error) {
|
||||
rules := strings.Split(allowlist, ",")
|
||||
for _, rule := range rules {
|
||||
includeRules := make([]string, 0)
|
||||
omitRules := make([]string, 0)
|
||||
for _, rule := range strings.Split(allowlist, ",") {
|
||||
if strings.Contains(rule, "://") {
|
||||
return nil, fmt.Errorf("allowlist %q contained ://", rule)
|
||||
}
|
||||
if len(rule) > 1 && rule[0] == '!' {
|
||||
omitRules = append(omitRules, rule[1:])
|
||||
} else {
|
||||
includeRules = append(includeRules, rule)
|
||||
}
|
||||
}
|
||||
return &RepoAllowlistChecker{
|
||||
rules: rules,
|
||||
includeRules: includeRules,
|
||||
omitRules: omitRules,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -45,7 +53,13 @@ func NewRepoAllowlistChecker(allowlist string) (*RepoAllowlistChecker, error) {
|
||||
// otherwise.
|
||||
func (r *RepoAllowlistChecker) IsAllowlisted(repoFullName string, vcsHostname string) bool {
|
||||
candidate := fmt.Sprintf("%s/%s", vcsHostname, repoFullName)
|
||||
for _, rule := range r.rules {
|
||||
shouldInclude := r.matchesAtLeastOneRule(r.includeRules, candidate)
|
||||
shouldOmit := r.matchesAtLeastOneRule(r.omitRules, candidate)
|
||||
return shouldInclude && !shouldOmit
|
||||
}
|
||||
|
||||
func (r *RepoAllowlistChecker) matchesAtLeastOneRule(rules []string, candidate string) bool {
|
||||
for _, rule := range rules {
|
||||
if r.matchesRule(rule, candidate) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -175,6 +175,20 @@ func TestRepoAllowlistChecker_IsAllowlisted(t *testing.T) {
|
||||
"github.com",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"should exclude with negative match",
|
||||
"github.com/owner/*,!github.com/owner/badrepo",
|
||||
"owner/badrepo",
|
||||
"github.com",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"should match if with negative rule doesn't match",
|
||||
"github.com/owner/*,!github.com/owner/badrepo",
|
||||
"owner/otherrepo",
|
||||
"github.com",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
|
||||
Reference in New Issue
Block a user