fix(catalog-backend-module-azure): fix ReDoS regex, URL encoding, error message, and missing deps

Signed-off-by: Lokesh Kaki <lokeshkaki1@gmail.com>
This commit is contained in:
Lokesh Kaki
2026-03-15 20:12:12 -05:00
parent 31ce5da2ea
commit bf7aeb5e31
2 changed files with 29 additions and 6 deletions
@@ -55,9 +55,11 @@
"@azure/storage-blob": "^12.5.0",
"@backstage/backend-plugin-api": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/integration": "workspace:^",
"@backstage/plugin-catalog-common": "workspace:^",
"@backstage/plugin-catalog-node": "workspace:^",
"@backstage/plugin-events-node": "workspace:^",
"uuid": "^11.0.0"
},
"devDependencies": {
@@ -154,9 +154,18 @@ function toLocationUrl(options: {
return undefined;
}
const url = new URL(options.remoteUrl);
const branch = branchNameFromRef(options.branchRef);
const branchSuffix = branch ? `&version=GB${branch}` : '';
return encodeURI(`${options.remoteUrl}?path=${options.path}${branchSuffix}`);
// Encode each path segment individually to protect against special chars while
// preserving '/' separators, which is what Azure DevOps expects in the path param.
const encodedPath = options.path
.split('/')
.map(encodeURIComponent)
.join('/');
url.search = branch
? `path=${encodedPath}&version=GB${encodeURIComponent(branch)}`
: `path=${encodedPath}`;
return url.toString();
}
function toCommitUrl(
@@ -359,11 +368,16 @@ function replaceRepoNameInRemoteUrl(
if (!remoteUrl || !repoName) {
return undefined;
}
const match = remoteUrl.match(/^(.*\/_git\/)([^/?#]+)(.*)$/);
if (!match) {
const gitMarker = '/_git/';
const gitIdx = remoteUrl.indexOf(gitMarker);
if (gitIdx === -1) {
return undefined;
}
return `${match[1]}${repoName}${match[3]}`;
const prefix = remoteUrl.slice(0, gitIdx + gitMarker.length);
const rest = remoteUrl.slice(gitIdx + gitMarker.length);
const endIdx = rest.search(/[/?#]/);
const suffix = endIdx === -1 ? '' : rest.slice(endIdx);
return `${prefix}${repoName}${suffix}`;
}
async function onPushEvent(
@@ -465,11 +479,18 @@ async function onRepositoryEvent(
if (eventType === 'git.repo.renamed' && toUrl) {
const oldName = asString(resource?.oldName);
if (!oldName) {
return {
result: 'ignored',
reason: 'Azure DevOps repository renamed event is missing oldName',
};
}
const fromUrl = replaceRepoNameInRemoteUrl(toUrl, oldName);
if (!fromUrl) {
return {
result: 'ignored',
reason: 'Azure DevOps repository renamed event is missing oldName',
reason:
'Azure DevOps repository renamed event has an unexpected repository.remoteUrl format',
};
}