Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1177,8 +1177,10 @@ jobs:
if [[ "$(System.PullRequest.TargetBranch)" != "" ]]; then
# If CI is set to shallow fetch, target branch should be expilictly fetched.
git fetch origin --depth=1 $(System.PullRequest.TargetBranch)
python scripts/ci/check_aliases_source_url.py --src=HEAD --tgt=origin/$(System.PullRequest.TargetBranch)
azdev linter --ci-exclusions --min-severity medium --repo=./ --src=HEAD --tgt=origin/$(System.PullRequest.TargetBranch)
else
python scripts/ci/check_aliases_source_url.py --src=HEAD --tgt=HEAD~1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In the non-PR path, --tgt=HEAD~1 only diffs against the last commit, which means multi-commit pushes could bypass the check. Consider using the default branch (e.g., origin/dev) as the target instead, so all new changes are covered.

azdev linter --ci-exclusions --min-severity medium
Comment thread
msarfraz marked this conversation as resolved.
fi

Expand Down
94 changes: 94 additions & 0 deletions scripts/ci/check_aliases_source_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env python

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

"""Fail CI if forbidden raw GitHub aliases URL is introduced in new diff lines."""

import argparse
import re
import subprocess
import sys


FORBIDDEN_URL_PATTERN = re.compile(
r"https://raw\.githubusercontent\.com/Azure/azure-rest-api-specs/[A-Za-z0-9._/-]+/arm-compute/quickstart-templates/aliases\.json"
Comment thread
msarfraz marked this conversation as resolved.
Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The regex only matches the exact azure-rest-api-specs/.../aliases.json path. If someone introduces a different raw.githubusercontent.com URL for other files, this check won't catch it. The PR's stated goal is to block GitHub URLs in network-isolated environments, so the pattern should be broader —
e.g., simply matching https://raw.githubusercontent.com/.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The regex is updated to match base URL "https://raw.githubusercontent.com" in the code. The documentation, tests, scripts and recordings directories are excluded from validation to avoid false positives

)
RECOMMENDED_ALIAS_URL = "https://azcliprod.blob.core.windows.net/cli/vm/aliases.json"

Comment thread
msarfraz marked this conversation as resolved.
Outdated

def _run_diff(src: str, tgt: str, cached: bool = False) -> str:
cmd = ["git", "diff", "--unified=0", "--no-color"]
if cached:
cmd.append("--cached")
else:
cmd.append(f"{tgt}...{src}")

proc = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=False,
)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or "git diff failed")
return proc.stdout


def _find_violations(diff_text: str):
violations = []
current_file = ""

for line in diff_text.splitlines():
if line.startswith("+++ b/"):
current_file = line[6:]
continue

if not line.startswith("+") or line.startswith("+++"):
continue

added_line = line[1:]
if FORBIDDEN_URL_PATTERN.search(added_line):
violations.append((current_file or "<unknown>", added_line.strip()))

return violations


def main() -> int:
parser = argparse.ArgumentParser(description="Check diff for forbidden raw aliases URL usage.")
parser.add_argument("--src", default="HEAD", help="Source ref/commit for git diff.")
parser.add_argument("--tgt", default="HEAD~1", help="Target ref/commit for git diff.")
parser.add_argument("--cached", action="store_true", help="Check staged changes in git index.")
args = parser.parse_args()

try:
diff_text = _run_diff(src=args.src, tgt=args.tgt, cached=args.cached)
except Exception as ex: # pylint: disable=broad-except
if args.cached:
print(f"Unable to evaluate staged diff: {ex}", file=sys.stderr)
else:
print(f"Unable to evaluate diff between '{args.tgt}' and '{args.src}': {ex}", file=sys.stderr)
return 1

violations = _find_violations(diff_text)
if not violations:
print("No forbidden aliases source URL found in added lines.")
return 0

print("Found forbidden aliases source URL in this change:", file=sys.stderr)
for file_path, content in violations:
print(f" - {file_path}: {content}", file=sys.stderr)

print(
f"Use '{RECOMMENDED_ALIAS_URL}' instead of raw GitHub URLs for aliases.json.",
file=sys.stderr,
)
return 1


if __name__ == "__main__":
sys.exit(main())

2 changes: 1 addition & 1 deletion src/azure-cli-core/azure/cli/core/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,8 +502,8 @@ class CloudNameEnum: # pylint: disable=too-few-public-methods
active_directory_resource_id='https://management.sovcloud-api.fr/',
active_directory_graph_resource_id='https://graph.svc.sovcloud.fr/',
microsoft_graph_resource_id='https://graph.svc.sovcloud.fr',
vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json',
media_resource_id='https://rest.media.sovcloud-api.fr',
vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json',
Comment thread
msarfraz marked this conversation as resolved.
Outdated
ossrdbms_resource_id='https://ossrdbms-aad.database.sovcloud-api.fr',
portal='https://portal.sovcloud-azure.fr'),
suffixes=CloudSuffixes(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interactions:
uri: https://management.azure.com/metadata/endpoints?api-version=2022-09-01
response:
body:
string: '{"portal":"https://portal.azure.com","authentication":{"loginEndpoint":"https://login.microsoftonline.com","audiences":["https://management.core.windows.net/","https://management.azure.com/"],"tenant":"common","identityProvider":"AAD"},"media":"https://rest.media.azure.net","graphAudience":"https://graph.windows.net/","graph":"https://graph.windows.net/","name":"AzureCloud","suffixes":{"azureDataLakeStoreFileSystem":"azuredatalakestore.net","acrLoginServer":"azurecr.io","sqlServerHostname":"database.windows.net","azureDataLakeAnalyticsCatalogAndJob":"azuredatalakeanalytics.net","keyVaultDns":"vault.azure.net","storage":"core.windows.net","azureFrontDoorEndpointSuffix":"azurefd.net","storageSyncEndpointSuffix":"afs.azure.net","mhsmDns":"managedhsm.azure.net","mysqlServerEndpoint":"mysql.database.azure.com","postgresqlServerEndpoint":"postgres.database.azure.com","mariadbServerEndpoint":"mariadb.database.azure.com","synapseAnalytics":"dev.azuresynapse.net","attestationEndpoint":"attest.azure.net"},"batch":"https://batch.core.windows.net/","resourceManager":"https://management.azure.com/","vmImageAliasDoc":"https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json","activeDirectoryDataLake":"https://datalake.azure.net/","sqlManagement":"https://management.core.windows.net:8443/","microsoftGraphResourceId":"https://graph.microsoft.com/","appInsightsResourceId":"https://api.applicationinsights.io","appInsightsTelemetryChannelResourceId":"https://dc.applicationinsights.azure.com/v2/track","attestationResourceId":"https://attest.azure.net","synapseAnalyticsResourceId":"https://dev.azuresynapse.net","logAnalyticsResourceId":"https://api.loganalytics.io","ossrDbmsResourceId":"https://ossrdbms-aad.database.windows.net"}'
string: '{"portal":"https://portal.azure.com","authentication":{"loginEndpoint":"https://login.microsoftonline.com","audiences":["https://management.core.windows.net/","https://management.azure.com/"],"tenant":"common","identityProvider":"AAD"},"media":"https://rest.media.azure.net","graphAudience":"https://graph.windows.net/","graph":"https://graph.windows.net/","name":"AzureCloud","suffixes":{"azureDataLakeStoreFileSystem":"azuredatalakestore.net","acrLoginServer":"azurecr.io","sqlServerHostname":"database.windows.net","azureDataLakeAnalyticsCatalogAndJob":"azuredatalakeanalytics.net","keyVaultDns":"vault.azure.net","storage":"core.windows.net","azureFrontDoorEndpointSuffix":"azurefd.net","storageSyncEndpointSuffix":"afs.azure.net","mhsmDns":"managedhsm.azure.net","mysqlServerEndpoint":"mysql.database.azure.com","postgresqlServerEndpoint":"postgres.database.azure.com","mariadbServerEndpoint":"mariadb.database.azure.com","synapseAnalytics":"dev.azuresynapse.net","attestationEndpoint":"attest.azure.net"},"batch":"https://batch.core.windows.net/","resourceManager":"https://management.azure.com/","vmImageAliasDoc":"https://azcliprod.blob.core.windows.net/cli/vm/aliases_master.json","activeDirectoryDataLake":"https://datalake.azure.net/","sqlManagement":"https://management.core.windows.net:8443/","microsoftGraphResourceId":"https://graph.microsoft.com/","appInsightsResourceId":"https://api.applicationinsights.io","appInsightsTelemetryChannelResourceId":"https://dc.applicationinsights.azure.com/v2/track","attestationResourceId":"https://attest.azure.net","synapseAnalyticsResourceId":"https://dev.azuresynapse.net","logAnalyticsResourceId":"https://api.loganalytics.io","ossrDbmsResourceId":"https://ossrdbms-aad.database.windows.net"}'
headers:
cache-control:
- no-cache
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ interactions:
User-Agent:
- python-requests/2.25.1
method: GET
uri: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json
uri: https://azcliprod.blob.core.windows.net/cli/vm/aliases_master.json
response:
body:
string: "{\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json\",\n
Expand Down
Loading