microsoft / terraform-provider-azuredevops

Terraform Azure DevOps provider
https://www.terraform.io/docs/providers/azuredevops/
MIT License
379 stars 268 forks source link

[Feature Request] Allow azuredevops_git_permissions to assign users #1096

Open rubenaster opened 2 months ago

rubenaster commented 2 months ago

Community Note

Description

Currently, azuredevops_git_permissions allows only to use groups as service principals, but not just single users. It also explicitly informs about that.

In general you're able to configure repository permissions for single user. My request is to reflect this also in the resource.

New or Affected Resource(s)

Potential Terraform Configuration

data "azuredevops_users" "build_service" {
  principal_name = azuredevops_project.main.id
}

resource "azuredevops_git_permissions" "project_build_service" {
  project_id    = azuredevops_git_repository.project.project_id
  repository_id = azuredevops_git_repository.projectid

  principal = data.azuredevops_users.build_service.id
  permissions = {
    GenericContribute = "Allow"
  }
}
ialexj commented 1 month ago

My use case for this is to set the permissions for the build service user on a repository, likely same as OP.

This is a workaround using local-exec, found to be working on stock Terraform Cloud agents:

data "azuredevops_client_config" "org" {}

data "azuredevops_project" "project" {
  project_id = var.project_id
}

locals {
  organization_name  = regex("https?://.+?/(.+?)/", data.azuredevops_client_config.org.organization_url)[0]
  build_service_name = "${data.azuredevops_project.project.name} Build Service (${local.organization_name})"
}

resource "azuredevops_git_repository" "repo" {
  # ...
}

resource "terraform_data" "assign_build_user_permissions" {
  lifecycle {
    replace_triggered_by = [
      azuredevops_git_repository.repo
    ]
  }

  provisioner "local-exec" {
    interpreter = ["/bin/bash", "-c"]

    command = replace(<<-EOT
      DESCRIPTOR=$(curl "https://vssps.dev.azure.com/$ORGNAME/_apis/identities" --get --data "searchFilter=DisplayName" --data-urlencode "filterValue=$BUILDUSER" --data 'api-version=7.0-preview' --location -u ":$AZDO_PERSONAL_ACCESS_TOKEN" -s -f | jq -r '.value[].descriptor')
      curl "https://dev.azure.com/$ORGNAME/_apis/AccessControlEntries/2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87?api-version=7.0-preview" --data $${JSONTEMPLATE//@DESCRIPTOR/$DESCRIPTOR} -u ":$AZDO_PERSONAL_ACCESS_TOKEN" -H 'Content-Type: application/json' -s -f
      EOT
    , "\r", "") # convert to unix newlines (otherwise $DESCRIPTOR ends up with an extra \r)

    environment = {
      BUILDUSER = local.build_service_name
      ORGNAME   = local.organization_name
      JSONTEMPLATE = jsonencode({
        token = "repoV2/${data.azuredevops_project.project.project_id}/${azuredevops_git_repository.repo.id}"
        merge = true
        accessControlEntries = [
          # GenericContribute, CreateTag, PullRequestContribute
          for allow in [4, 32, 16384] : { descriptor = "@DESCRIPTOR", allow = allow }
        ]
      })
    }
  }
}
Jaroslav24 commented 4 weeks ago

I found that it is possible to assign permissions to users. Even though the docs say it is only possible to groups. What you need is a user descriptor. You can get one for Build Service using data block:

data "azuredevops_users" "build_service" {
  principal_name = azuredevops_project.main.id
}

resource "azuredevops_git_permissions" "project_build_service" {
  project_id    = azuredevops_git_repository.project.project_id
  repository_id = azuredevops_git_repository.projectid
//Then use the descriptor in principal param
  principal = data.azuredevops_users.build_service.users[0].descriptor
  permissions = {
    GenericContribute = "Allow"
  }
}
ialexj commented 2 weeks ago

Worked for me as well with a few syntax tweaks, here's my final code:

data "azuredevops_users" "build_service" {
  principal_name = var.project_id
}

resource "azuredevops_git_permissions" "build_service_permission" {
  project_id    = var.project_id
  repository_id = azuredevops_git_repository.repo.id
  principal     = one(data.azuredevops_users.build_service.users).descriptor
  permissions = {
    GenericContribute     = "Allow"
    #PullRequestContribute = "Allow"
    #CreateTag             = "Allow"
  }
}