Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 13, 2026

Verify-Links.ps1 only checked links against remote state, missing cases where PRs delete referenced files or create files for non-Azure orgs.

Changes

Verify-Links.ps1:

  • Added localBuildTargetBranch parameter to receive PR target branch from $env:SYSTEM_PULLREQUEST_TARGETBRANCH
  • Extended GitHub link matching from Azure org only to any org (microsoft, Azure, etc.)
  • Added support for raw.githubusercontent.com URLs alongside github.com/blob|tree format
  • Check local filesystem when link matches currentRepo + targetBranch:
    • File exists locally → pass (PR creates/maintains file)
    • File missing locally → fail (PR would break link)
    • Otherwise → HTTP check (existing behavior)
  • Security: Use [^#?]* instead of .* in regex (ReDoS prevention), log relative paths only

verify-links.yml:

  • Pass -localBuildTargetBranch "$env:SYSTEM_PULLREQUEST_TARGETBRANCH" to script

Example

# Before: Link to Azure org only
'^https://github.com/(?<org>Azure)/(?<repo>[^/]+)/(?:blob|tree)/(main|.*_[^/]+|.*/v[^/]+)/(?<path>.*)$'

# After: Any org + target branch check
'^https://github\.com/(?<org>[^/]+)/(?<repo>[^/]+)/(?:blob|tree)/(?<branch>[^/]+)/(?<path>[^#?]*)$'

if ($localBuildTargetBranch -and $branch -eq $localBuildTargetBranch) {
  Test-Path (Join-Path $localBuildRepoPath $path)  # Validate against PR workspace
}

Impact:

  • PR deleting docs/guide.md with link to it now fails validation
  • PR creating docs/new.md with link to it now passes validation

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • aka.ms
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • azure.github.io
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • cla.opensource.microsoft.com
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • go.microsoft.com
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • insiders.vscode.dev
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • learn.microsoft.com
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • marketplace.eclipse.org
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • marketplace.visualstudio.com
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • modelcontextprotocol.io
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • opensource.microsoft.com
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • plugins.jetbrains.com
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • spec.modelcontextprotocol.io
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • vscode.dev
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)
  • www.nuget.org
    • Triggering command: /usr/bin/pwsh pwsh /tmp/test_real_repo.ps1 (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-String -Pattern &#39;Checked|broken&#39; (dns block)
    • Triggering command: /usr/bin/pwsh pwsh -c &amp; ./eng/common/scripts/Verify-Links.ps1 -urls ./README.md -localBuildRepoName &#39;microsoft/mcp&#39; -localBuildRepoPath . -localBuildTargetBranch &#39;main&#39; -recursive $false 2&gt;&amp;1 | Select-Object -Last 5 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Link validation doesn't catch GH link changes in the current PR</issue_title>
<issue_description>Readmes are checked for broken links using Verify-Links.ps1. That script checks that the URLs in a markdown or html file are valid and don't return an error result, e.g. 404.

The current script doesn't detect that a PR will be deleting a file that a url targets. It also doesn't detect that a change creates a file that a url targets when the github org isn't Azure.

We should improve the script so that:

  • validation fails if the current PR deletes a file that a url references (when the url targets main, etc)
  • validation succeeds if the current PR creates a file that a url references (even when the github org != 'azure')</issue_description>

Comments on the Issue (you are @copilot in this section)

@hallipr Copilot, update the link validation script to check for local files when verifying any github link that would be based off of the current repo and target branch. I want a link check to fail if this pr **would** break a link.

For example, when the target branch of a PR is main, any github.com or githubusercontent.com that point to the current repo and the branch main should check the local filesystem for the file rather than the current remote state of the url.</comment_new>


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 4 commits January 13, 2026 23:45
Co-authored-by: hallipr <1291634+hallipr@users.noreply.github.com>
Co-authored-by: hallipr <1291634+hallipr@users.noreply.github.com>
…groups

Co-authored-by: hallipr <1291634+hallipr@users.noreply.github.com>
Co-authored-by: hallipr <1291634+hallipr@users.noreply.github.com>
Copilot AI changed the title [WIP] Update link validation to catch URL changes in PRs Validate GitHub links against local filesystem to catch PR-induced broken links Jan 13, 2026
Copilot AI requested a review from hallipr January 13, 2026 23:56
Comment on lines 32 to +34
-localBuildRepoName "$env:BUILD_REPOSITORY_NAME"
-localBuildRepoPath $(Build.SourcesDirectory)
-localBuildTargetBranch "$env:SYSTEM_PULLREQUEST_TARGETBRANCH"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer yaml variable syntax over environment variable syntax

Suggested change
-localBuildRepoName "$env:BUILD_REPOSITORY_NAME"
-localBuildRepoPath $(Build.SourcesDirectory)
-localBuildTargetBranch "$env:SYSTEM_PULLREQUEST_TARGETBRANCH"
-localBuildRepoName "$(Build.Repository.Name)"
-localBuildRepoPath $(Build.SourcesDirectory)
-localBuildTargetBranch "$(System.PullRequest.TargetBranch)"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

Link validation doesn't catch GH link changes in the current PR

2 participants