microsoft / terraform-provider-azuredevops

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

`azuredevops_pipeline_authorization` resource does not allow resource_id for repositories in another project. #1038

Open WillEdMatsypie opened 2 months ago

WillEdMatsypie commented 2 months ago

Community Note

Terraform (and Azure DevOps Provider) Version

terraform -v
Terraform v1.7.5
on darwin_arm64
+ provider registry.terraform.io/microsoft/azuredevops v1.0.1

Affected Resource(s)

Terraform Configuration Files

## Contains the repo
data "azuredevops_project" "a" {
  name = "Project A"
}

## Contains consuming pipelines
data "azuredevops_project" "b" {
  name = "Project B"
}

## Get Repo ID from Project A
data "azuredevops_git_repository" "my_repo" {
  project_id = data.azuredevops_project.a.id
  name       = "my-repo"
}

## Authorise _all_ pipelines in Project B to use my_repo
resource "azuredevops_pipeline_authorization" "auth" {
  project_id  = data.azuredevops_project.b.id
  resource_id = "${data.azuredevops_project.a.id}.${data.azuredevops_git_repository.my_repo.id}"
  type        = "repository"
}

Debug Output

azuredevops_pipeline_authorization.auth: Creating...
ā•·
ā”‚ Error:  creating authorized resource: Resource id exceeds maximum length of 100.
ā”‚ 
ā”‚   with azuredevops_pipeline_authorization.auth,
ā”‚   on main.tf line 51, in resource "azuredevops_pipeline_authorization" "auth":
ā”‚   51: resource "azuredevops_pipeline_authorization" "auth" {
ā”‚ 
ā•µ

Expected Behavior

This should authorise my_repo for all pipelines in Project B.

The Azure DevOps API for adding pipeline permissions for repositories accepts resource_id of a repo in another Project provided it is given of format "${project_id}.${repo_id}" - I have been able to do this via the API using python requests, however it seems to not be possible to give IDs of this format in terraform.

I have also attempted without the project_id prefixed but that results in an error that the resource cannot be found, likely due to it only checking the current project given by project_id.

Actual Behavior

Terraform throws an error that the Resource ID exceeds the maximum length of 100. This should not be true as the length of the 2 GUIDs concatenated with a . is actually 73 characters, I would assume under the hood this is maybe trying to add the project ID of Project B again to the front of the resource_id hence the longer string.

At any rate, as per the Expected Behaviour, the API accepts resource_ids of this format for referencing repositories in different projects.

Steps to Reproduce

  1. Create 2 projects (Project A and Project B)
  2. Create a repo in Project A called my_repo
  3. Apply the above terraform code

You can also test this works via the API with the API reference here, simply replace resource ID with this format "${project_id}.${repo_id}"

https://learn.microsoft.com/en-us/rest/api/azure/devops/approvalsandchecks/pipeline-permissions/update-pipeline-permisions-for-resource?view=azure-devops-rest-7.1&tabs=HTTP

WillEdMatsypie commented 2 months ago

I see this is actually fixed in #973 which has been merged - great solution, nice one! Any ideas when this version will be available to consume?

xuzhang3 commented 1 month ago

soon, working on it

WillEdMatsypie commented 1 month ago

Following up on this - I see this has been made available now.

However, notably when I use the resource to authorise access to a repository for all pipelines in another project, I get a timeout every time ā€œwaiting for pipeline authorization ready. timeout while waiting for state to become ā€˜succeed, failedā€™ (last state: ā€˜waitingā€™, timeout: 2m0s)ā€

Notably when I check via the API, I see that the pipeline permission has in fact enabled! But terraform never gets a success response. I can also enable this via the API and get a success response using the same token

WillEdMatsypie commented 1 month ago

@xuzhang3 - From further inspection with some local testing, it looks like the method for ā€œGetPipelinePermissionsForResourceā€ gets nil for ā€œAllPipelinesā€, whereas ā€œUpdatePipelinePermissionsForResourceā€ itself gets a value back - so seems like something may be off thereā€¦ I am sadly still learning Go, so not in much of a position to make suggestions, but I think thereā€™s something inconsistent coming from the Go client maybe?

(Note this is specifically when going cross project on repo permissions, within the same project behaves entirely as expected)

EDIT: Notably, with the same token, the Get API endpoint returns AllPipelines and not null when called from python - so seems likely that it is to do with the client maybe?

EDIT 2: I think I found the issue - the checkPipelineAuthorization function doesnā€™t make use of pipelineProjectId, so it is checking the permissions in the wrong project. Updating this locally allows the resource creation to succeed after 10s.