Repository: runatlantis/atlantis (language: go)

Issue:
Drop team name support in `--gh-team-allowlist`
<!--- Please keep this note for the community --->

### Community Note

* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request. Searching for pre-existing feature requests helps us consolidate datapoints for identical requirements into a single place, thank you!
* Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request.
* If you are interested in working on this issue or have submitted a pull request, please leave a comment.

<!--- Thank you for keeping this note for the community --->

---

<!---
When filing a bug, please include the following headings if possible.
Any example text in this template can be deleted.
--->

### Overview of the Issue

The `--gh-team-allowlist` flag accepts both team names and team slugs in its rules. Sources: [docs](https://github.com/runatlantis/atlantis/blob/main/runatlantis.io/docs/server-configuration.md#--gh-team-allowlist) and [code](https://github.com/runatlantis/atlantis/blob/main/server/events/vcs/github_client.go#L1055).
This is for historical reasons: [first](https://github.com/runatlantis/atlantis/pull/1694) it used just names, [then](https://github.com/runatlantis/atlantis/pull/2719) slug support was added and names were never dropped.

This could become a security concern if someone who's not supposed to be allowed to run a given command, has permissions to create a GitHub team within your organization, since they could configure the name (which need not be unique) to the that of the team that's configured in the allowlist. Slugs, on the other hand, are unique across a GitHub organization.

This is also a problem even if you use slugs in your allowlist. The [underlying logic](https://github.com/runatlantis/atlantis/blob/main/server/events/command/team_allowlist_checker.go#L82-L86) that matches teams to rules does a logical OR of name and slug, meaning a would-be intruder could just name their new team with the slug of the allowed team to escalate their privilege into running restricted Atlantis commands.

The `--gitlab-group-allowlist` flag is not affected. Its group matching logic is slugs only. Sources: [docs](https://github.com/runatlantis/atlantis/blob/main/runatlantis.io/docs/server-configuration.md#--gitlab-group-allowlist) and [code](https://github.com/runatlantis/atlantis/blob/main/server/events/vcs/gitlab_client.go#L667).

At the time of writing, no other supported VCS provider supports command allowlisting. Sources: [Azure DevOps](https://github.com/runatlantis/atlantis/blob/main/server/events/vcs/azuredevops_client.go#L412), BitBucket [Cloud](https://github.com/runatlantis/atlantis/blob/main/server/events/vcs/bitbucketcloud/client.go#L355) and [Server](https://github.com/runatlantis/atlantis/blob/main/server/events/vcs/bitbucketserver/client.go#L354), [Gitea](https://github.com/runatlantis/atlantis/blob/main/server/events/vcs/gitea/client.go#L418), 


### Reproduction Steps

1. Run Atlantis with `--gh-team-allowlist='*:plan, Appliers:apply'`.
2. Create a GitHub team with slug `appliers` and name `Appliers`. Don't add yourself to it.
3. Create another team with slug `intruders` and name `Appliers`. Add yourself to this one.
4. Trigger `atlantis apply` on an open PR.


### Additional Context

This issue has been [previously discussed in Slack](https://cloud-native.slack.com/archives/C06DMCR0NFQ/p1744103200468099) and the preferred solution is to drop GitHub team names support from the `--gh-team-allowlist` flag, allowing only slugs to be used.


Discussion / hints:

Fix patch:
diff --git a/runatlantis.io/docs/server-configuration.md b/runatlantis.io/docs/server-configuration.md
index 1e658a2440..88fc25fa8c 100644
--- a/runatlantis.io/docs/server-configuration.md
+++ b/runatlantis.io/docs/server-configuration.md
@@ -686,12 +686,14 @@ based on the organization or user that triggered the webhook.
 ### `--gh-team-allowlist`
 
   ```bash
-  atlantis server --gh-team-allowlist="myteam:plan, secteam:apply, DevOps Team:apply, DevOps Team:import"
+  atlantis server --gh-team-allowlist="myteam:plan, secteam:apply, devops-team:apply, devops-team:import"
   # or
-  ATLANTIS_GH_TEAM_ALLOWLIST="myteam:plan, secteam:apply, DevOps Team:apply, DevOps Team:import"
+  ATLANTIS_GH_TEAM_ALLOWLIST="myteam:plan, secteam:apply, devops-team:apply, devops-team:import"
   ```
 
-  In versions v0.21.0 and later, the GitHub team name can be a name or a slug.
+  In versions v0.35.0 and later, the GitHub team name can only be a slug because it is immutable.
+
+  In versions between v0.21.0 and v0.34.0, the GitHub team name can be a name or a slug.
 
   In versions v0.20.1 and below, the Github team name required the case sensitive team name.
 
@@ -699,11 +701,6 @@ based on the organization or user that triggered the webhook.
 
   By default, any team can plan and apply.
 
-  ::: warning NOTE
-  You should use the Team name as the variable, not the slug, even if it has spaces or special characters.
-  i.e., "Engineering Team:plan, Infrastructure Team:apply"
-  :::
-
 ### `--gh-token`
 
   ```bash
diff --git a/server/events/vcs/github_client.go b/server/events/vcs/github_client.go
index f36e6af432..1bcb461b6d 100644
--- a/server/events/vcs/github_client.go
+++ b/server/events/vcs/github_client.go
@@ -1052,7 +1052,7 @@ func (g *GithubClient) GetTeamNamesForUser(logger logging.SimpleLogging, repo mo
 			return nil, err
 		}
 		for _, edge := range q.Organization.Teams.Edges {
-			teamNames = append(teamNames, edge.Node.Name, edge.Node.Slug)
+			teamNames = append(teamNames, edge.Node.Slug)
 		}
 		if !q.Organization.Teams.PageInfo.HasNextPage {
 			break


Test patch:
diff --git a/server/events/vcs/github_client_test.go b/server/events/vcs/github_client_test.go
index f71a629f3e..2483642f4c 100644
--- a/server/events/vcs/github_client_test.go
+++ b/server/events/vcs/github_client_test.go
@@ -1406,7 +1406,7 @@ func TestGithubClient_GetTeamNamesForUser(t *testing.T) {
 			Username: "testuser",
 		})
 	Ok(t, err)
-	Equals(t, []string{"Frontend Developers", "frontend-developers", "Employees", "employees"}, teams)
+	Equals(t, []string{"frontend-developers", "employees"}, teams)
 }
 
 func TestGithubClient_DiscardReviews(t *testing.T) {