The Issue
Whilst working on an Azure DevOps YAML pipeline for a solution that used Git Submodules we hit a problem with the checkout of the repo and submodule using the YAML
jobs:
- job: 'Build'
steps:
- checkout: self
submodules: true
It got the main Git repo, but failed with the following error
git submodule sync
git --config-env=http.https://myorg@dev.azure.com.extraheader=env_var_http.https://myorg@dev.azure.com.extraheader submodule update --init --force
Submodule 'Library' (https://myorg@dev.azure.com/myorg/myproject/_git/Library) registered for path 'Library'
Cloning into 'D:/a/1/s/Library'...
remote: TF401019: The Git repository with name or identifier Library does not exist or you do not have permissions for the operation you are attempting.
The Analysis
The issue is that the build agent access token was scoped to only the repo containing the YAML pipeline and not the submodule repo, even though they are in the same Azure DevOps Team Project.
This was not because of a lack of permissions for the build service account, but that the Azure DevOps Team Project pipelines setting ‘Protect access to repositories in YAML pipelines’ was enabled. This setting restricts the access of the build agent to only the repo containing the YAML pipeline, or ones referenced explicitly in the pipeline.
The Solution
The obvious solution is to disable the ‘Protect access to repositories in YAML pipelines’ setting for the Team Project. However, this may not be possible due to security requirements. In our case this setting was being enforced at the Team Project Collection level and we could not alter it.
But luckily there is a workaround.
-
In the YAML reference the Git Submodule and use the
checkout
task to clone into some folder (the folder is unimportant as we will never actually use it). -
You can then call the main
checkout
with thesubmodules
parameter set totrue
. This will now work because the agent access token is now scoped to both the repo the YAML is in and the submodule you manually referenced
name: $(Build.DefinitionName)
trigger:
branches:
include: [ main ]
resources:
repositories:
- repository: Library # the submodule
type: git
name: Library
pool:
vmImage: windows-latest
stages:
- stage: 'Build_Packages'
jobs:
- job: 'Build'
steps:
- checkout: Library # the throwaway checkout
path: './s/SomeTmpPath/Library'
- checkout: self # the main checkout
submodules: true
Note: You can’t seem to get away with just adding the reference, the explicit checkout of the referenced submodule repo is required, else you still get the permissions error.
So, a hacky solution, but it works!