Skip to content

[agent-issue]: normalize legacy Azure Repos remotes for deterministic integrity locks #1494

Description

@krubenok

Submission requirements

  • I generated this issue with an agent that used .github/agents/ado-aw.agent.md.
  • I reviewed the generated issue and confirm it is being filed directly in githubnext/ado-aw.

Problem summary

In v0.44.0, equivalent Azure Repos remote URL formats can produce different generated lock files. This makes integrity-sensitive output depend on the clone's configured origin rather than only on the workflow source.

The legacy Azure Repos URL family is partially supported, but URLs containing the common /DefaultCollection/ segment are not recognized during compile-time remote inference. In that environment, ado-aw-metadata and aw_info.json are generated with empty org and repo fields. Azure Pipelines checks out the same repository using the equivalent modern dev.azure.com form, which is recognized and produces populated fields. The in-pipeline integrity check therefore recompiles to different bytes and fails despite identical source markdown.

There is a workaround: temporarily rewrite the local origin to the modern URL before compiling, then restore it. However, this is a potentially serious footgun because the lock can appear valid locally while remaining dependent on an undocumented piece of developer-specific clone configuration. It is easy to regenerate and commit a lock that predictably fails only in CI.

A secondary failure-reporting issue obscures the root cause. After integrity verification fails, the ado-script download/install steps are skipped under the default success condition. Trigger-gated execution-context steps use explicit conditions that replace the implicit succeeded() condition, so matching PR/work-item context steps can still run and fail with misleading MODULE_NOT_FOUND errors.

Reproduction details

  1. Clone an Azure Repos repository with this generic legacy origin shape:

    https://exampleorg.visualstudio.com/DefaultCollection/Example%20Project/_git/example-repo
    
  2. Compile an unchanged agent markdown file with ado-aw compile.

  3. Observe generated metadata containing:

    {"org":"","repo":""}
  4. Run the generated pipeline. Azure Pipelines exposes/checks out the equivalent repository using the modern form:

    https://dev.azure.com/exampleorg/Example%20Project/_git/example-repo
    
  5. The in-pipeline ado-aw check recompilation infers:

    {"org":"exampleorg","repo":"example-repo"}
  6. Integrity verification fails because both the generated ado-aw-metadata marker and aw_info.json content differ.

  7. If PR or linked-work-item execution context is enabled and the trigger matches, those steps may subsequently run without the skipped ado-script bundle and report MODULE_NOT_FOUND, masking the integrity failure.

Expected behavior: equivalent supported Azure Repos remote URL families produce byte-identical locks, and context preparation does not run after an earlier step fails.

Proposed next step

  1. Extend parse_ado_remote() normalization to support legacy https://{org}.visualstudio.com[/DefaultCollection]/{project}/_git/{repo} URLs and map them to the same canonical context as https://dev.azure.com/{org}/{project}/_git/{repo}.
  2. Add regression coverage that compiles the same workflow from temporary repositories configured with the legacy and modern remotes and asserts byte-identical complete lock output.
  3. Consider explicit source-identity overrides, such as compile --org/--repo or dedicated front-matter fields, so integrity metadata can be deterministic when remote inference is unavailable or noncanonical. The existing Azure DevOps tool org option should not be conflated with lock source identity.
  4. Preserve the default success gate on trigger-conditioned execution-context steps by emitting and(succeeded(), <trigger condition>). Audit all trigger-gated contributors, including PR, PR checks, work item, schedule, CI push, pipeline trigger, and manual context.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions