Skip to content

feat(azuredevops): run a hub on Azure Pipelines - #25

Merged
AlexeyShalaev merged 1 commit into
masterfrom
feat/azure-pipelines-hub
Oct 9, 2026
Merged

AlexeyShalaev merged 1 commit into
masterfrom
feat/azure-pipelines-hub

Conversation

@AlexeyShalaev

Copy link
Copy Markdown
Member

A hub can now live in Azure Repos of Azure DevOps Services and run in Azure Pipelines, as a hub on Bitbucket Cloud runs in Bitbucket Pipelines. Built from Microsoft's documentation and tested against stand-ins; nothing here has run on a live organization (the guide lists what a first live run must confirm).

Detection and the hub channel

  • hubch detects Azure Pipelines (TF_BUILD=True). Only a build of an Azure Repos repository (Build.Repository.Provider TfsGit) of Azure DevOps Services (System.CollectionUri on dev.azure.com or <org>.visualstudio.com) has a hub; anything else has no fingerprint, and distribute refuses.
  • The fingerprint is dev.azure.com/<repository id>, the GUID lowercase. Repository ids are unique across organizations and survive renames, so it names no organization; --hub-fp and previous_fingerprints take it as they take a Bitbucket UUID.
  • The hub channel uses the job access token, System.AccessToken, which the step maps into SYSTEM_ACCESSTOKEN. No variable names the default branch, so it reads the branch, its tip and the project's visibility (from the repository, else the project) before any guard.
  • plan --comment creates a closed comment thread, so that a policy requiring resolved comments never waits on it. It is plain Markdown with the link reference definition marker, as on Bitbucket, and touchmark edits only the comment of its own identity (connectionData).

Guards and doctor

  • distribute and doctor need a deployment job to the environment touchmark-distribute (ENVIRONMENT_NAME) and the default branch read by the channel.
  • The write key lives in the variable group touchmark-distribute, kept to the default branch by a Branch control check. A job's token is not known to read checks, so write_isolation: platform needs security.reason there, like Bitbucket's.
  • doctor --hub-token reads the variables of the hub's pipelines, the project's variable groups with the checks and pipeline permissions of each, and the project's pipeline settings. A key in a pipeline variable fails. A key in a group is ok only behind a Branch control check that admits the default branch alone; it warns without Verify branch protection.
  • The grading continues:
    • a group open to every pipeline of the project fails without Verify branch protection: Branch control compares only the branch name, which another repository's pipeline on its own main shares;
    • a check whose branches cannot be read is unknown, and a branch named without refs/heads/ warns;
    • the new check pipeline-settings fails while "Limit variables that can be set at queue time" is off (a queue-time BASH_ENV or DOCKER_HOST reaches the steps that hold the key) and warns on a job token scope wider than the project.
  • A hub without providers takes its organization from the origin remote outside CI (https://dev.azure.com/<org>/…, the SSH form, <org>.visualstudio.com). doctor --hub-token picks the hub's organization the same way when hub.yml lists several.

Output

  • The Azure agent runs any ##vso[…] it finds in a step's output. Under TF_BUILD=True everything touchmark prints goes through a writer that breaks every ##vso[, also one split across writes.

Config, tests and docs

  • The implicit provider of a hub without providers comes from System.CollectionUri in CI.
  • setup azure-devops points at the manual steps.
  • TestTemplateAzurePipelines checks the template's azure-pipelines.yml and its step template without Azure. It plays a pull request, pushes, both schedules and both manual runs, with a small evaluator of the stages' conditions; it runs in CI next to TestTemplatePipelines.
  • Docs: "A hub on Azure DevOps", CI, security, providers, environment, hub reference, glossary, threat model, e2e. The guide makes the plan comment optional: the right it needs also lets a pull request build vote, so it is granted only with required reviewers. The README and the home page now list Bitbucket Cloud and Azure DevOps among the platforms.

A hub can live in Azure Repos of Azure DevOps Services and run in Azure
Pipelines. hubch detects it (TF_BUILD=True, a TfsGit repository of an
organization on dev.azure.com or <org>.visualstudio.com); its fingerprint
is dev.azure.com/<repository id>, the GUID lowercase. The hub channel uses
the job access token mapped into SYSTEM_ACCESSTOKEN: it reads the default
branch, its tip and the project's visibility, and keeps plan's comment as
a closed thread, plain Markdown, found by the token's own identity.

distribute and doctor need a deployment job to the environment
touchmark-distribute and the default branch read by the channel. The
write key lives in the variable group touchmark-distribute behind a
Branch control check, which a job cannot read: write_isolation platform
needs security.reason there, as on Bitbucket. doctor --hub-token reads
the hub's pipeline variables, the project's variable groups with their
checks and pipeline permissions, and the project's pipeline settings; a
key in a pipeline variable fails, a group without a check admitting the
default branch alone fails, an open group without Verify branch
protection fails, and variables settable at queue time fail.

Under TF_BUILD=True everything touchmark prints goes through a writer that
breaks every "##vso[", so that no text of a platform or a target becomes
a logging command of the agent. Outside CI a hub without providers takes
its organization from the origin remote. TestTemplateAzurePipelines plays
the template's azure-pipelines.yml without Azure. Docs: a hub on Azure
DevOps, CI, security, providers, environment, references, threat model.
@AlexeyShalaev
AlexeyShalaev merged commit f66aeb4 into master Oct 9, 2026
22 checks passed
@AlexeyShalaev
AlexeyShalaev deleted the feat/azure-pipelines-hub branch October 9, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant