From 55459dbae14b2aa15b5f062cfdeb023f9dd61eb7 Mon Sep 17 00:00:00 2001 From: Alex Torres Date: Tue, 2 Sep 2025 17:19:16 -0700 Subject: [PATCH 1/6] Add validation at execution start --- .../resources.resjson/en-US/resources.resjson | 10 ++- Tasks/NuGetAuthenticateV1/main.ts | 62 +++++++++++++++---- Tasks/NuGetAuthenticateV1/task.json | 12 ++-- Tasks/NuGetAuthenticateV1/task.loc.json | 10 ++- .../NuGetAuthenticateV1/taskJsonOverride.json | 2 +- 5 files changed, 74 insertions(+), 22 deletions(-) diff --git a/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson b/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson index 2e81c04e9daf..8bf6e087fff0 100644 --- a/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson @@ -7,13 +7,17 @@ "loc.input.help.nuGetServiceConnections": "Comma-separated list of NuGet service connection names for feeds outside this organization/collection. For feeds in this organization/collection, leave this blank; the build’s credentials are used automatically.", "loc.input.label.forceReinstallCredentialProvider": "Reinstall the credential provider even if already installed", "loc.input.help.forceReinstallCredentialProvider": "If the credential provider is already installed in the user profile, determines if it is overwritten with the task-provided credential provider. This may upgrade (or potentially downgrade) the credential provider.", - "loc.input.help.feedUrl": "If this is set, workloadIdentityServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "loc.input.help.feedUrl": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "loc.input.label.feedUrl": "Azure Artifacts URL", "loc.input.help.workloadIdentityServiceConnection": "If this is set, feedUrl is required. All other inputs are ignored.", "loc.input.label.workloadIdentityServiceConnection": "'Azure DevOps' Service Connection", "loc.messages.Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and workloadIdentityServiceConnection must be set together.", + "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", + "loc.messages.Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", + "loc.messages.Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", "loc.messages.Info_AddingFederatedFeedAuth": "Unable to get federated credentials from service connection", "loc.messages.Info_SuccessAddingFederatedFeedAuth": "Adding auth information from service connection %s for feed %s", - "loc.messages.FailedToGetServiceConnectionAuth": "Successfully added auth for feed %s." + "loc.messages.FailedToGetServiceConnectionAuth": "Successfully added auth for feed %s.", + "loc.messages.Warn_IgnoringFeedUrl": "Ignoring feedUrl" } \ No newline at end of file diff --git a/Tasks/NuGetAuthenticateV1/main.ts b/Tasks/NuGetAuthenticateV1/main.ts index df5e32fdb5af..8b02579c4dda 100644 --- a/Tasks/NuGetAuthenticateV1/main.ts +++ b/Tasks/NuGetAuthenticateV1/main.ts @@ -7,6 +7,7 @@ import { installCredProviderToUserProfile, configureCredProvider, configureCredP import { ProtocolType } from 'azure-pipelines-tasks-artifacts-common/protocols'; import { getPackagingServiceConnections } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils' import { emitTelemetry } from 'azure-pipelines-tasks-artifacts-common/telemetry' +import { ServiceConnection } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils'; async function main(): Promise { let forceReinstallCredentialProvider = null; @@ -15,16 +16,45 @@ async function main(): Promise { try { tl.setResourcePath(path.join(__dirname, 'task.json')); +#if WIF + + var feedUrl = tl.getInput("feedUrl"); + var entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); + var serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); + + // Validate input combination + // Case 1: NuGet && WIF -> Error + if (serviceConnections.length > 0 && entraWifServiceConnectionName) { + tl.setResult(tl.TaskResult.Failed, tl.loc("Error_NuGetWithWIFNotSupported")); + return; + } + + // Case 2: !NuGet && WIF -> Success + if (entraWifServiceConnectionName) { + // Happy path + } + else { + // Case 3: !WIF && feedUrl -> Warn and ignore + if (feedUrl) { + feedUrl = null; + tl.warning(tl.loc("Warn_IgnoringFeedUrl")); + + // In the future, we will move towards breaking behavior + // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); + } + } + + // Validate input is valid feed URL + if (feedUrl && !validateFeedUrl(feedUrl)) { + tl.setResult(tl.TaskResult.Failed, tl.loc("Error_InvalidFeedUrl", feedUrl)); + } + // Install the credential provider forceReinstallCredentialProvider = tl.getBoolInput("forceReinstallCredentialProvider", false); await installCredProviderToUserProfile(forceReinstallCredentialProvider); -#if WIF - const feedUrl = tl.getInput("feedUrl"); - const entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); - // Only cross-org feedUrls are supported with Azure Devops service connections. If feedUrl is internal, the task will fail. - if (feedUrl && entraWifServiceConnectionName) { + if (entraWifServiceConnectionName && feedUrl ) { tl.debug(tl.loc("Info_AddingFederatedFeedAuth", entraWifServiceConnectionName, feedUrl)); await configureEntraCredProvider(ProtocolType.NuGet, entraWifServiceConnectionName, feedUrl); federatedFeedAuthSuccessCount++; @@ -33,13 +63,11 @@ async function main(): Promise { return; } // If the user doesn't provide a feedUrl, use the Azure Devops service connection to replace the Build Service - else if (!feedUrl && entraWifServiceConnectionName) { + else if (entraWifServiceConnectionName && !feedUrl) { configureCredProviderForSameOrganizationFeeds(ProtocolType.NuGet, entraWifServiceConnectionName); return; } - else if (feedUrl) { - throw new Error(tl.loc("Error_MissingFeedUrlOrServiceConnection")); - } + #endif // Configure the credential provider for both same-organization feeds and service connections @@ -50,9 +78,21 @@ async function main(): Promise { } finally { emitTelemetry("Packaging", "NuGetAuthenticateV1", { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, - "FederatedFeedAuthCount": federatedFeedAuthSuccessCount + "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, + "isFeedUrlIncluded": !!tl.getInput("feedUrl"), + "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, + "isServiceConnectionIncluded": !!serviceConnections.length }); } } -main(); +/** + * Validates that the feedUrl is a valid Azure DevOps feed URL. + * Throws an error if the URL is not valid. + * Returns true if the feedUrl is valid. + */ +function validateFeedUrl(feedUrl: string): boolean { + return !!feedUrl && /^https:\/\/(dev\.azure\.com|[\w-]+\.visualstudio\.com)\/[\w-]+\/_packaging\/[\w-]+\/nuget\/v3\/index\.json$/i.test(feedUrl); +} + +main(); \ No newline at end of file diff --git a/Tasks/NuGetAuthenticateV1/task.json b/Tasks/NuGetAuthenticateV1/task.json index 208176b00cfd..131cfb08cd48 100644 --- a/Tasks/NuGetAuthenticateV1/task.json +++ b/Tasks/NuGetAuthenticateV1/task.json @@ -13,8 +13,8 @@ ], "version": { "Major": 1, - "Minor": 247, - "Patch": 4 + "Minor": 263, + "Patch": 3 }, "minimumAgentVersion": "2.144.0", "instanceNameFormat": "NuGet Authenticate", @@ -54,9 +54,13 @@ }, "messages": { "Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and workloadIdentityServiceConnection must be set together.", + "Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", + "Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", + "Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", "FailedToGetServiceConnectionAuth": "Unable to get federated credentials from service connection", "Info_AddingFederatedFeedAuth": "Adding auth information from service connection %s for feed %s", - "Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s." + "Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s.", + "Warn_IgnoringFeedUrl": "Ignoring feedUrl" } } \ No newline at end of file diff --git a/Tasks/NuGetAuthenticateV1/task.loc.json b/Tasks/NuGetAuthenticateV1/task.loc.json index 9e75a479e31f..2c6fe77c8051 100644 --- a/Tasks/NuGetAuthenticateV1/task.loc.json +++ b/Tasks/NuGetAuthenticateV1/task.loc.json @@ -13,8 +13,8 @@ ], "version": { "Major": 1, - "Minor": 247, - "Patch": 4 + "Minor": 263, + "Patch": 1 }, "minimumAgentVersion": "2.144.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", @@ -54,9 +54,13 @@ }, "messages": { "Error_ServiceConnectionExists": "ms-resource:loc.messages.Error_ServiceConnectionExists", + "Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", "Error_MissingFeedUrlOrServiceConnection": "ms-resource:loc.messages.Error_MissingFeedUrlOrServiceConnection", + "Error_NuGetWithFeedUrlNotSupported": "ms-resource:loc.messages.Error_NuGetWithFeedUrlNotSupported", + "Error_NuGetWithWIFNotSupported": "ms-resource:loc.messages.Error_NuGetWithWIFNotSupported", "FailedToGetServiceConnectionAuth": "ms-resource:loc.messages.FailedToGetServiceConnectionAuth", "Info_AddingFederatedFeedAuth": "ms-resource:loc.messages.Info_AddingFederatedFeedAuth", - "Info_SuccessAddingFederatedFeedAuth": "ms-resource:loc.messages.Info_SuccessAddingFederatedFeedAuth" + "Info_SuccessAddingFederatedFeedAuth": "ms-resource:loc.messages.Info_SuccessAddingFederatedFeedAuth", + "Warn_IgnoringFeedUrl": "ms-resource:loc.messages.Warn_IgnoringFeedUrl" } } \ No newline at end of file diff --git a/Tasks/NuGetAuthenticateV1/taskJsonOverride.json b/Tasks/NuGetAuthenticateV1/taskJsonOverride.json index bb0bb163e775..70b7badfec79 100644 --- a/Tasks/NuGetAuthenticateV1/taskJsonOverride.json +++ b/Tasks/NuGetAuthenticateV1/taskJsonOverride.json @@ -15,7 +15,7 @@ { "name": "feedUrl", "label": "Azure Artifacts URL", - "helpMarkDown": "If this is set, workloadIdentityServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "type": "string", "defaultValue": "", "required": false From 8fdab119ce6d6a2ac5c779a8c8313798b03ca132 Mon Sep 17 00:00:00 2001 From: Alex Torres Date: Tue, 2 Sep 2025 23:22:19 -0700 Subject: [PATCH 2/6] Streamline failure cases --- Tasks/NuGetAuthenticateV1/main.ts | 42 +++++++-------- Tasks/NuGetAuthenticateV1/task.json | 2 +- Tasks/NuGetAuthenticateV1/task.loc.json | 2 +- _generated/NuGetAuthenticateV1.versionmap.txt | 4 +- .../resources.resjson/en-US/resources.resjson | 8 ++- _generated/NuGetAuthenticateV1/main.ts | 24 ++++++--- _generated/NuGetAuthenticateV1/task.json | 16 +++--- _generated/NuGetAuthenticateV1/task.loc.json | 14 +++-- .../NuGetAuthenticateV1/taskJsonOverride.json | 2 +- .../resources.resjson/en-US/resources.resjson | 10 ++-- _generated/NuGetAuthenticateV1_Wif/main.ts | 52 +++++++++++++++---- _generated/NuGetAuthenticateV1_Wif/task.json | 18 ++++--- .../NuGetAuthenticateV1_Wif/task.loc.json | 14 +++-- .../taskJsonOverride.json | 2 +- 14 files changed, 137 insertions(+), 73 deletions(-) diff --git a/Tasks/NuGetAuthenticateV1/main.ts b/Tasks/NuGetAuthenticateV1/main.ts index 8b02579c4dda..50c80a1f15fc 100644 --- a/Tasks/NuGetAuthenticateV1/main.ts +++ b/Tasks/NuGetAuthenticateV1/main.ts @@ -13,37 +13,25 @@ async function main(): Promise { let forceReinstallCredentialProvider = null; let federatedFeedAuthSuccessCount: number = 0; + var feedUrl; + var entraWifServiceConnectionName; + var serviceConnections; + try { tl.setResourcePath(path.join(__dirname, 'task.json')); #if WIF - var feedUrl = tl.getInput("feedUrl"); - var entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); - var serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); + feedUrl = tl.getInput("feedUrl"); + entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); + serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); - // Validate input combination - // Case 1: NuGet && WIF -> Error + // Failure case: User provides inputs for both NuGet & WIF Service Connections if (serviceConnections.length > 0 && entraWifServiceConnectionName) { tl.setResult(tl.TaskResult.Failed, tl.loc("Error_NuGetWithWIFNotSupported")); return; } - // Case 2: !NuGet && WIF -> Success - if (entraWifServiceConnectionName) { - // Happy path - } - else { - // Case 3: !WIF && feedUrl -> Warn and ignore - if (feedUrl) { - feedUrl = null; - tl.warning(tl.loc("Warn_IgnoringFeedUrl")); - - // In the future, we will move towards breaking behavior - // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); - } - } - // Validate input is valid feed URL if (feedUrl && !validateFeedUrl(feedUrl)) { tl.setResult(tl.TaskResult.Failed, tl.loc("Error_InvalidFeedUrl", feedUrl)); @@ -66,12 +54,19 @@ async function main(): Promise { else if (entraWifServiceConnectionName && !feedUrl) { configureCredProviderForSameOrganizationFeeds(ProtocolType.NuGet, entraWifServiceConnectionName); return; - } + } + // Warning case: User provides feedUrl without providing a WIF service connection + // In the future, we will shift to breaking behavior + else if (feedUrl) { + tl.warning(tl.loc("Warn_IgnoringFeedUrl")); + feedUrl = null; + // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); + } #endif // Configure the credential provider for both same-organization feeds and service connections - var serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); + serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); await configureCredProvider(ProtocolType.NuGet, serviceConnections); } catch (error) { tl.setResult(tl.TaskResult.Failed, error); @@ -88,8 +83,7 @@ async function main(): Promise { /** * Validates that the feedUrl is a valid Azure DevOps feed URL. - * Throws an error if the URL is not valid. - * Returns true if the feedUrl is valid. + * Returns true if the feedUrl is valid, false otherwise. */ function validateFeedUrl(feedUrl: string): boolean { return !!feedUrl && /^https:\/\/(dev\.azure\.com|[\w-]+\.visualstudio\.com)\/[\w-]+\/_packaging\/[\w-]+\/nuget\/v3\/index\.json$/i.test(feedUrl); diff --git a/Tasks/NuGetAuthenticateV1/task.json b/Tasks/NuGetAuthenticateV1/task.json index 131cfb08cd48..bf23e0ce07b7 100644 --- a/Tasks/NuGetAuthenticateV1/task.json +++ b/Tasks/NuGetAuthenticateV1/task.json @@ -14,7 +14,7 @@ "version": { "Major": 1, "Minor": 263, - "Patch": 3 + "Patch": 0 }, "minimumAgentVersion": "2.144.0", "instanceNameFormat": "NuGet Authenticate", diff --git a/Tasks/NuGetAuthenticateV1/task.loc.json b/Tasks/NuGetAuthenticateV1/task.loc.json index 2c6fe77c8051..a7f99e6a1784 100644 --- a/Tasks/NuGetAuthenticateV1/task.loc.json +++ b/Tasks/NuGetAuthenticateV1/task.loc.json @@ -14,7 +14,7 @@ "version": { "Major": 1, "Minor": 263, - "Patch": 1 + "Patch": 0 }, "minimumAgentVersion": "2.144.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", diff --git a/_generated/NuGetAuthenticateV1.versionmap.txt b/_generated/NuGetAuthenticateV1.versionmap.txt index 987b1ead41c7..209d7a74fc76 100644 --- a/_generated/NuGetAuthenticateV1.versionmap.txt +++ b/_generated/NuGetAuthenticateV1.versionmap.txt @@ -1,2 +1,2 @@ -Default|1.247.4 -wif_242|1.247.5 +Default|1.263.0 +wif_242|1.263.1 diff --git a/_generated/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson b/_generated/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson index b772db129a3a..65961b26b103 100644 --- a/_generated/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson +++ b/_generated/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson @@ -8,8 +8,12 @@ "loc.input.label.forceReinstallCredentialProvider": "Reinstall the credential provider even if already installed", "loc.input.help.forceReinstallCredentialProvider": "If the credential provider is already installed in the user profile, determines if it is overwritten with the task-provided credential provider. This may upgrade (or potentially downgrade) the credential provider.", "loc.messages.Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and workloadIdentityServiceConnection must be set together.", + "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", + "loc.messages.Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", + "loc.messages.Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", "loc.messages.FailedToGetServiceConnectionAuth": "Unable to get federated credentials from service connection", "loc.messages.Info_AddingFederatedFeedAuth": "Adding auth information from service connection %s for feed %s", - "loc.messages.Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s." + "loc.messages.Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s.", + "loc.messages.Warn_IgnoringFeedUrl": "Ignoring feedUrl" } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1/main.ts b/_generated/NuGetAuthenticateV1/main.ts index 690ab25307ce..12f0e1e3d898 100644 --- a/_generated/NuGetAuthenticateV1/main.ts +++ b/_generated/NuGetAuthenticateV1/main.ts @@ -4,30 +4,42 @@ import { installCredProviderToUserProfile, configureCredProvider, configureCredP import { ProtocolType } from 'azure-pipelines-tasks-artifacts-common/protocols'; import { getPackagingServiceConnections } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils' import { emitTelemetry } from 'azure-pipelines-tasks-artifacts-common/telemetry' +import { ServiceConnection } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils'; async function main(): Promise { let forceReinstallCredentialProvider = null; let federatedFeedAuthSuccessCount: number = 0; + var feedUrl; + var entraWifServiceConnectionName; + var serviceConnections; + try { tl.setResourcePath(path.join(__dirname, 'task.json')); - // Install the credential provider - forceReinstallCredentialProvider = tl.getBoolInput("forceReinstallCredentialProvider", false); - await installCredProviderToUserProfile(forceReinstallCredentialProvider); - // Configure the credential provider for both same-organization feeds and service connections - var serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); + serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); await configureCredProvider(ProtocolType.NuGet, serviceConnections); } catch (error) { tl.setResult(tl.TaskResult.Failed, error); } finally { emitTelemetry("Packaging", "NuGetAuthenticateV1", { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, - "FederatedFeedAuthCount": federatedFeedAuthSuccessCount + "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, + "isFeedUrlIncluded": !!tl.getInput("feedUrl"), + "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, + "isServiceConnectionIncluded": !!serviceConnections.length }); } } +/** + * Validates that the feedUrl is a valid Azure DevOps feed URL. + * Returns true if the feedUrl is valid, false otherwise. + */ +function validateFeedUrl(feedUrl: string): boolean { + return !!feedUrl && /^https:\/\/(dev\.azure\.com|[\w-]+\.visualstudio\.com)\/[\w-]+\/_packaging\/[\w-]+\/nuget\/v3\/index\.json$/i.test(feedUrl); +} + main(); diff --git a/_generated/NuGetAuthenticateV1/task.json b/_generated/NuGetAuthenticateV1/task.json index 59962e1b2e35..b73e6ec5b1d9 100644 --- a/_generated/NuGetAuthenticateV1/task.json +++ b/_generated/NuGetAuthenticateV1/task.json @@ -13,8 +13,8 @@ ], "version": { "Major": 1, - "Minor": 247, - "Patch": 4 + "Minor": 263, + "Patch": 0 }, "minimumAgentVersion": "2.144.0", "instanceNameFormat": "NuGet Authenticate", @@ -54,14 +54,18 @@ }, "messages": { "Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and workloadIdentityServiceConnection must be set together.", + "Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", + "Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", + "Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", "FailedToGetServiceConnectionAuth": "Unable to get federated credentials from service connection", "Info_AddingFederatedFeedAuth": "Adding auth information from service connection %s for feed %s", - "Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s." + "Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s.", + "Warn_IgnoringFeedUrl": "Ignoring feedUrl" }, "_buildConfigMapping": { - "Default": "1.247.4", + "Default": "1.263.0", "LocalPackages": "1.249.4", - "wif_242": "1.247.5" + "wif_242": "1.263.1" } } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1/task.loc.json b/_generated/NuGetAuthenticateV1/task.loc.json index 3d990a130a79..29d1acbf3242 100644 --- a/_generated/NuGetAuthenticateV1/task.loc.json +++ b/_generated/NuGetAuthenticateV1/task.loc.json @@ -13,8 +13,8 @@ ], "version": { "Major": 1, - "Minor": 247, - "Patch": 4 + "Minor": 263, + "Patch": 0 }, "minimumAgentVersion": "2.144.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", @@ -54,14 +54,18 @@ }, "messages": { "Error_ServiceConnectionExists": "ms-resource:loc.messages.Error_ServiceConnectionExists", + "Error_InvalidFeedUrl": "ms-resource:loc.messages.Error_InvalidFeedUrl", "Error_MissingFeedUrlOrServiceConnection": "ms-resource:loc.messages.Error_MissingFeedUrlOrServiceConnection", + "Error_NuGetWithFeedUrlNotSupported": "ms-resource:loc.messages.Error_NuGetWithFeedUrlNotSupported", + "Error_NuGetWithWIFNotSupported": "ms-resource:loc.messages.Error_NuGetWithWIFNotSupported", "FailedToGetServiceConnectionAuth": "ms-resource:loc.messages.FailedToGetServiceConnectionAuth", "Info_AddingFederatedFeedAuth": "ms-resource:loc.messages.Info_AddingFederatedFeedAuth", - "Info_SuccessAddingFederatedFeedAuth": "ms-resource:loc.messages.Info_SuccessAddingFederatedFeedAuth" + "Info_SuccessAddingFederatedFeedAuth": "ms-resource:loc.messages.Info_SuccessAddingFederatedFeedAuth", + "Warn_IgnoringFeedUrl": "ms-resource:loc.messages.Warn_IgnoringFeedUrl" }, "_buildConfigMapping": { - "Default": "1.247.4", + "Default": "1.263.0", "LocalPackages": "1.249.4", - "wif_242": "1.247.5" + "wif_242": "1.263.1" } } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1/taskJsonOverride.json b/_generated/NuGetAuthenticateV1/taskJsonOverride.json index bb0bb163e775..70b7badfec79 100644 --- a/_generated/NuGetAuthenticateV1/taskJsonOverride.json +++ b/_generated/NuGetAuthenticateV1/taskJsonOverride.json @@ -15,7 +15,7 @@ { "name": "feedUrl", "label": "Azure Artifacts URL", - "helpMarkDown": "If this is set, workloadIdentityServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "type": "string", "defaultValue": "", "required": false diff --git a/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson b/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson index 8cd3d269e089..d454e8b834a4 100644 --- a/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson +++ b/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson @@ -6,14 +6,18 @@ "loc.input.label.workloadIdentityServiceConnection": "'Azure DevOps' Service Connection", "loc.input.help.workloadIdentityServiceConnection": "If this is set, feedUrl is required. All other inputs are ignored.", "loc.input.label.feedUrl": "Azure Artifacts URL", - "loc.input.help.feedUrl": "If this is set, workloadIdentityServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "loc.input.help.feedUrl": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "loc.input.label.forceReinstallCredentialProvider": "Reinstall the credential provider even if already installed", "loc.input.help.forceReinstallCredentialProvider": "If the credential provider is already installed in the user profile, determines if it is overwritten with the task-provided credential provider. This may upgrade (or potentially downgrade) the credential provider.", "loc.input.label.nuGetServiceConnections": "Service connection credentials for feeds outside this organization", "loc.input.help.nuGetServiceConnections": "Comma-separated list of NuGet service connection names for feeds outside this organization/collection. For feeds in this organization/collection, leave this blank; the build’s credentials are used automatically.", "loc.messages.Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and workloadIdentityServiceConnection must be set together.", + "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", + "loc.messages.Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", + "loc.messages.Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", "loc.messages.FailedToGetServiceConnectionAuth": "Unable to get federated credentials from service connection", "loc.messages.Info_AddingFederatedFeedAuth": "Adding auth information from service connection %s for feed %s", - "loc.messages.Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s." + "loc.messages.Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s.", + "loc.messages.Warn_IgnoringFeedUrl": "Ignoring feedUrl" } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1_Wif/main.ts b/_generated/NuGetAuthenticateV1_Wif/main.ts index e7aa94b8a429..fbddb09a165e 100644 --- a/_generated/NuGetAuthenticateV1_Wif/main.ts +++ b/_generated/NuGetAuthenticateV1_Wif/main.ts @@ -5,23 +5,41 @@ import { installCredProviderToUserProfile, configureCredProvider, configureCredP import { ProtocolType } from 'azure-pipelines-tasks-artifacts-common/protocols'; import { getPackagingServiceConnections } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils' import { emitTelemetry } from 'azure-pipelines-tasks-artifacts-common/telemetry' +import { ServiceConnection } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils'; async function main(): Promise { let forceReinstallCredentialProvider = null; let federatedFeedAuthSuccessCount: number = 0; + var feedUrl; + var entraWifServiceConnectionName; + var serviceConnections; + try { tl.setResourcePath(path.join(__dirname, 'task.json')); + + feedUrl = tl.getInput("feedUrl"); + entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); + serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); + + // Failure case: User provides inputs for both NuGet & WIF Service Connections + if (serviceConnections.length > 0 && entraWifServiceConnectionName) { + tl.setResult(tl.TaskResult.Failed, tl.loc("Error_NuGetWithWIFNotSupported")); + return; + } + + // Validate input is valid feed URL + if (feedUrl && !validateFeedUrl(feedUrl)) { + tl.setResult(tl.TaskResult.Failed, tl.loc("Error_InvalidFeedUrl", feedUrl)); + } + // Install the credential provider forceReinstallCredentialProvider = tl.getBoolInput("forceReinstallCredentialProvider", false); await installCredProviderToUserProfile(forceReinstallCredentialProvider); - const feedUrl = tl.getInput("feedUrl"); - const entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); - // Only cross-org feedUrls are supported with Azure Devops service connections. If feedUrl is internal, the task will fail. - if (feedUrl && entraWifServiceConnectionName) { + if (entraWifServiceConnectionName && feedUrl ) { tl.debug(tl.loc("Info_AddingFederatedFeedAuth", entraWifServiceConnectionName, feedUrl)); await configureEntraCredProvider(ProtocolType.NuGet, entraWifServiceConnectionName, feedUrl); federatedFeedAuthSuccessCount++; @@ -30,25 +48,41 @@ async function main(): Promise { return; } // If the user doesn't provide a feedUrl, use the Azure Devops service connection to replace the Build Service - else if (!feedUrl && entraWifServiceConnectionName) { + else if (entraWifServiceConnectionName && !feedUrl) { configureCredProviderForSameOrganizationFeeds(ProtocolType.NuGet, entraWifServiceConnectionName); return; - } + } + // Warning case: User provides feedUrl without providing a WIF service connection + // In the future, we will shift to breaking behavior else if (feedUrl) { - throw new Error(tl.loc("Error_MissingFeedUrlOrServiceConnection")); + tl.warning(tl.loc("Warn_IgnoringFeedUrl")); + feedUrl = null; + // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); } + // Configure the credential provider for both same-organization feeds and service connections - var serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); + serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); await configureCredProvider(ProtocolType.NuGet, serviceConnections); } catch (error) { tl.setResult(tl.TaskResult.Failed, error); } finally { emitTelemetry("Packaging", "NuGetAuthenticateV1", { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, - "FederatedFeedAuthCount": federatedFeedAuthSuccessCount + "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, + "isFeedUrlIncluded": !!tl.getInput("feedUrl"), + "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, + "isServiceConnectionIncluded": !!serviceConnections.length }); } } +/** + * Validates that the feedUrl is a valid Azure DevOps feed URL. + * Returns true if the feedUrl is valid, false otherwise. + */ +function validateFeedUrl(feedUrl: string): boolean { + return !!feedUrl && /^https:\/\/(dev\.azure\.com|[\w-]+\.visualstudio\.com)\/[\w-]+\/_packaging\/[\w-]+\/nuget\/v3\/index\.json$/i.test(feedUrl); +} + main(); diff --git a/_generated/NuGetAuthenticateV1_Wif/task.json b/_generated/NuGetAuthenticateV1_Wif/task.json index bf2a4b1ec3ef..20a197326a8f 100644 --- a/_generated/NuGetAuthenticateV1_Wif/task.json +++ b/_generated/NuGetAuthenticateV1_Wif/task.json @@ -13,8 +13,8 @@ ], "version": { "Major": 1, - "Minor": 247, - "Patch": 5 + "Minor": 263, + "Patch": 1 }, "minimumAgentVersion": "2.144.0", "instanceNameFormat": "NuGet Authenticate", @@ -36,7 +36,7 @@ { "name": "feedUrl", "label": "Azure Artifacts URL", - "helpMarkDown": "If this is set, workloadIdentityServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "type": "string", "defaultValue": "", "required": false @@ -76,14 +76,18 @@ }, "messages": { "Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and workloadIdentityServiceConnection must be set together.", + "Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", + "Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", + "Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", "FailedToGetServiceConnectionAuth": "Unable to get federated credentials from service connection", "Info_AddingFederatedFeedAuth": "Adding auth information from service connection %s for feed %s", - "Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s." + "Info_SuccessAddingFederatedFeedAuth": "Successfully added auth for feed %s.", + "Warn_IgnoringFeedUrl": "Ignoring feedUrl" }, "_buildConfigMapping": { - "Default": "1.247.4", + "Default": "1.263.0", "LocalPackages": "1.249.4", - "wif_242": "1.247.5" + "wif_242": "1.263.1" } } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1_Wif/task.loc.json b/_generated/NuGetAuthenticateV1_Wif/task.loc.json index cb6cf3ca6020..a77c75f637a0 100644 --- a/_generated/NuGetAuthenticateV1_Wif/task.loc.json +++ b/_generated/NuGetAuthenticateV1_Wif/task.loc.json @@ -13,8 +13,8 @@ ], "version": { "Major": 1, - "Minor": 247, - "Patch": 5 + "Minor": 263, + "Patch": 1 }, "minimumAgentVersion": "2.144.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", @@ -76,14 +76,18 @@ }, "messages": { "Error_ServiceConnectionExists": "ms-resource:loc.messages.Error_ServiceConnectionExists", + "Error_InvalidFeedUrl": "ms-resource:loc.messages.Error_InvalidFeedUrl", "Error_MissingFeedUrlOrServiceConnection": "ms-resource:loc.messages.Error_MissingFeedUrlOrServiceConnection", + "Error_NuGetWithFeedUrlNotSupported": "ms-resource:loc.messages.Error_NuGetWithFeedUrlNotSupported", + "Error_NuGetWithWIFNotSupported": "ms-resource:loc.messages.Error_NuGetWithWIFNotSupported", "FailedToGetServiceConnectionAuth": "ms-resource:loc.messages.FailedToGetServiceConnectionAuth", "Info_AddingFederatedFeedAuth": "ms-resource:loc.messages.Info_AddingFederatedFeedAuth", - "Info_SuccessAddingFederatedFeedAuth": "ms-resource:loc.messages.Info_SuccessAddingFederatedFeedAuth" + "Info_SuccessAddingFederatedFeedAuth": "ms-resource:loc.messages.Info_SuccessAddingFederatedFeedAuth", + "Warn_IgnoringFeedUrl": "ms-resource:loc.messages.Warn_IgnoringFeedUrl" }, "_buildConfigMapping": { - "Default": "1.247.4", + "Default": "1.263.0", "LocalPackages": "1.249.4", - "wif_242": "1.247.5" + "wif_242": "1.263.1" } } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json index bb0bb163e775..70b7badfec79 100644 --- a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json +++ b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json @@ -15,7 +15,7 @@ { "name": "feedUrl", "label": "Azure Artifacts URL", - "helpMarkDown": "If this is set, workloadIdentityServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "type": "string", "defaultValue": "", "required": false From 138b0f5af208bd9c67e5a5a510e05f954908cd6f Mon Sep 17 00:00:00 2001 From: Alex Torres Date: Wed, 3 Sep 2025 00:31:00 -0700 Subject: [PATCH 3/6] Fail fast & display warning before configuring cred provider --- Tasks/NuGetAuthenticateV1/main.ts | 18 +++++++++++------- _generated/NuGetAuthenticateV1/main.ts | 1 + _generated/NuGetAuthenticateV1_Wif/main.ts | 18 +++++++++++------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Tasks/NuGetAuthenticateV1/main.ts b/Tasks/NuGetAuthenticateV1/main.ts index 50c80a1f15fc..1c4d4ab32044 100644 --- a/Tasks/NuGetAuthenticateV1/main.ts +++ b/Tasks/NuGetAuthenticateV1/main.ts @@ -32,6 +32,16 @@ async function main(): Promise { return; } + // Warning case: User provides feedUrl without providing a WIF service connection + // In the future, we will shift to breaking behavior + if (entraWifServiceConnectionName) { + // Happy path, continue with flow + } else if (feedUrl) { + tl.warning(tl.loc("Warn_IgnoringFeedUrl")); + feedUrl = null; + // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); + } + // Validate input is valid feed URL if (feedUrl && !validateFeedUrl(feedUrl)) { tl.setResult(tl.TaskResult.Failed, tl.loc("Error_InvalidFeedUrl", feedUrl)); @@ -55,13 +65,6 @@ async function main(): Promise { configureCredProviderForSameOrganizationFeeds(ProtocolType.NuGet, entraWifServiceConnectionName); return; } - // Warning case: User provides feedUrl without providing a WIF service connection - // In the future, we will shift to breaking behavior - else if (feedUrl) { - tl.warning(tl.loc("Warn_IgnoringFeedUrl")); - feedUrl = null; - // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); - } #endif @@ -75,6 +78,7 @@ async function main(): Promise { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, "isFeedUrlIncluded": !!tl.getInput("feedUrl"), + "isFeedUrlValid": validateFeedUrl(tl.getInput("feedUrl")), "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, "isServiceConnectionIncluded": !!serviceConnections.length }); diff --git a/_generated/NuGetAuthenticateV1/main.ts b/_generated/NuGetAuthenticateV1/main.ts index 12f0e1e3d898..697bed14f416 100644 --- a/_generated/NuGetAuthenticateV1/main.ts +++ b/_generated/NuGetAuthenticateV1/main.ts @@ -28,6 +28,7 @@ async function main(): Promise { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, "isFeedUrlIncluded": !!tl.getInput("feedUrl"), + "isFeedUrlValid": validateFeedUrl(tl.getInput("feedUrl")), "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, "isServiceConnectionIncluded": !!serviceConnections.length }); diff --git a/_generated/NuGetAuthenticateV1_Wif/main.ts b/_generated/NuGetAuthenticateV1_Wif/main.ts index fbddb09a165e..ce28d596ea50 100644 --- a/_generated/NuGetAuthenticateV1_Wif/main.ts +++ b/_generated/NuGetAuthenticateV1_Wif/main.ts @@ -29,6 +29,16 @@ async function main(): Promise { return; } + // Warning case: User provides feedUrl without providing a WIF service connection + // In the future, we will shift to breaking behavior + if (entraWifServiceConnectionName) { + // Happy path, continue with flow + } else if (feedUrl) { + tl.warning(tl.loc("Warn_IgnoringFeedUrl")); + feedUrl = null; + // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); + } + // Validate input is valid feed URL if (feedUrl && !validateFeedUrl(feedUrl)) { tl.setResult(tl.TaskResult.Failed, tl.loc("Error_InvalidFeedUrl", feedUrl)); @@ -52,13 +62,6 @@ async function main(): Promise { configureCredProviderForSameOrganizationFeeds(ProtocolType.NuGet, entraWifServiceConnectionName); return; } - // Warning case: User provides feedUrl without providing a WIF service connection - // In the future, we will shift to breaking behavior - else if (feedUrl) { - tl.warning(tl.loc("Warn_IgnoringFeedUrl")); - feedUrl = null; - // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); - } // Configure the credential provider for both same-organization feeds and service connections @@ -71,6 +74,7 @@ async function main(): Promise { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, "isFeedUrlIncluded": !!tl.getInput("feedUrl"), + "isFeedUrlValid": validateFeedUrl(tl.getInput("feedUrl")), "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, "isServiceConnectionIncluded": !!serviceConnections.length }); From 8e59cb2677feb4bc49248477b652afdddb6d604f Mon Sep 17 00:00:00 2001 From: Alex Torres Date: Wed, 3 Sep 2025 18:26:58 -0700 Subject: [PATCH 4/6] Add alias, tweak visibility conditions, feed validation --- .../resources.resjson/en-US/resources.resjson | 2 +- Tasks/NuGetAuthenticateV1/main.ts | 53 ++++++++++--------- Tasks/NuGetAuthenticateV1/task.json | 2 +- Tasks/NuGetAuthenticateV1/task.loc.json | 2 +- .../NuGetAuthenticateV1/taskJsonOverride.json | 10 ++-- .../taskJsonOverride.loc.json | 10 ++-- .../resources.resjson/en-US/resources.resjson | 2 +- _generated/NuGetAuthenticateV1/main.ts | 18 +++++-- _generated/NuGetAuthenticateV1/task.json | 2 +- .../NuGetAuthenticateV1/taskJsonOverride.json | 10 ++-- .../taskJsonOverride.loc.json | 10 ++-- .../resources.resjson/en-US/resources.resjson | 2 +- _generated/NuGetAuthenticateV1_Wif/main.ts | 51 +++++++++--------- _generated/NuGetAuthenticateV1_Wif/task.json | 14 +++-- .../NuGetAuthenticateV1_Wif/task.loc.json | 12 +++-- .../taskJsonOverride.json | 10 ++-- .../taskJsonOverride.loc.json | 10 ++-- 17 files changed, 134 insertions(+), 86 deletions(-) diff --git a/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson b/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson index 8bf6e087fff0..e9b8ceb3c868 100644 --- a/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson @@ -12,7 +12,7 @@ "loc.input.help.workloadIdentityServiceConnection": "If this is set, feedUrl is required. All other inputs are ignored.", "loc.input.label.workloadIdentityServiceConnection": "'Azure DevOps' Service Connection", "loc.messages.Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '%s' is not a valid Azure DevOps feed URL.", "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", "loc.messages.Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", "loc.messages.Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", diff --git a/Tasks/NuGetAuthenticateV1/main.ts b/Tasks/NuGetAuthenticateV1/main.ts index 1c4d4ab32044..5bef9ef031d9 100644 --- a/Tasks/NuGetAuthenticateV1/main.ts +++ b/Tasks/NuGetAuthenticateV1/main.ts @@ -20,37 +20,28 @@ async function main(): Promise { try { tl.setResourcePath(path.join(__dirname, 'task.json')); -#if WIF + // Install the credential provider + forceReinstallCredentialProvider = tl.getBoolInput("forceReinstallCredentialProvider", false); + await installCredProviderToUserProfile(forceReinstallCredentialProvider); - feedUrl = tl.getInput("feedUrl"); - entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); +#if WIF + entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); + feedUrl = tl.getInput("feedUrl", false); + // Failure case: User provides inputs for both NuGet & WIF Service Connections if (serviceConnections.length > 0 && entraWifServiceConnectionName) { tl.setResult(tl.TaskResult.Failed, tl.loc("Error_NuGetWithWIFNotSupported")); return; } - // Warning case: User provides feedUrl without providing a WIF service connection - // In the future, we will shift to breaking behavior - if (entraWifServiceConnectionName) { - // Happy path, continue with flow - } else if (feedUrl) { - tl.warning(tl.loc("Warn_IgnoringFeedUrl")); - feedUrl = null; - // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); - } - // Validate input is valid feed URL - if (feedUrl && !validateFeedUrl(feedUrl)) { + if (feedUrl && !isValidFeed(feedUrl)) { tl.setResult(tl.TaskResult.Failed, tl.loc("Error_InvalidFeedUrl", feedUrl)); + return; } - // Install the credential provider - forceReinstallCredentialProvider = tl.getBoolInput("forceReinstallCredentialProvider", false); - await installCredProviderToUserProfile(forceReinstallCredentialProvider); - // Only cross-org feedUrls are supported with Azure Devops service connections. If feedUrl is internal, the task will fail. if (entraWifServiceConnectionName && feedUrl ) { tl.debug(tl.loc("Info_AddingFederatedFeedAuth", entraWifServiceConnectionName, feedUrl)); @@ -59,17 +50,22 @@ async function main(): Promise { console.log(tl.loc("Info_SuccessAddingFederatedFeedAuth", feedUrl)); return; - } - // If the user doesn't provide a feedUrl, use the Azure Devops service connection to replace the Build Service - else if (entraWifServiceConnectionName && !feedUrl) { + } else if (entraWifServiceConnectionName && !feedUrl) { + // If the user doesn't provide a feedUrl, use the Azure Devops service connection to replace the Build Service configureCredProviderForSameOrganizationFeeds(ProtocolType.NuGet, entraWifServiceConnectionName); + return; - } + } else if (feedUrl) { + // Warning case: User provides feedUrl without providing a WIF service connection + // In the future, we will shift to breaking behavior + tl.warning(tl.loc("Warn_IgnoringFeedUrl")); + feedUrl = null; + // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); + } #endif // Configure the credential provider for both same-organization feeds and service connections - serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); await configureCredProvider(ProtocolType.NuGet, serviceConnections); } catch (error) { tl.setResult(tl.TaskResult.Failed, error); @@ -78,7 +74,7 @@ async function main(): Promise { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, "isFeedUrlIncluded": !!tl.getInput("feedUrl"), - "isFeedUrlValid": validateFeedUrl(tl.getInput("feedUrl")), + "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")), "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, "isServiceConnectionIncluded": !!serviceConnections.length }); @@ -89,8 +85,13 @@ async function main(): Promise { * Validates that the feedUrl is a valid Azure DevOps feed URL. * Returns true if the feedUrl is valid, false otherwise. */ -function validateFeedUrl(feedUrl: string): boolean { - return !!feedUrl && /^https:\/\/(dev\.azure\.com|[\w-]+\.visualstudio\.com)\/[\w-]+\/_packaging\/[\w-]+\/nuget\/v3\/index\.json$/i.test(feedUrl); +function isValidFeed(feedUrl?: string | null): boolean { + if (!feedUrl) return false; + const normalized = feedUrl.trim().replace(/^[\u2018\u2019\u201C\u201D'"]|['"\u2018\u2019\u201C\u201D]$/g, ''); + + const feedRegex = /^https:\/\/(?:[\w.-]+\.)?(?:dev\.azure\.com|visualstudio\.com|vsts\.me|codedev\.ms|devppe\.azure\.com|codeapp\.ms)(?:\/[^\/]+(?:\/[^\/]+)?)?\/_packaging\/[^\/]+\/nuget\/v3\/index\.json\/?$/i; + + return feedRegex.test(normalized); } main(); \ No newline at end of file diff --git a/Tasks/NuGetAuthenticateV1/task.json b/Tasks/NuGetAuthenticateV1/task.json index bf23e0ce07b7..15096e661e71 100644 --- a/Tasks/NuGetAuthenticateV1/task.json +++ b/Tasks/NuGetAuthenticateV1/task.json @@ -54,7 +54,7 @@ }, "messages": { "Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "Error_InvalidFeedUrl": "The provided feed URL '%s' is not a valid Azure DevOps feed URL.", "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", "Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", "Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", diff --git a/Tasks/NuGetAuthenticateV1/task.loc.json b/Tasks/NuGetAuthenticateV1/task.loc.json index a7f99e6a1784..caeb8e6cb6dd 100644 --- a/Tasks/NuGetAuthenticateV1/task.loc.json +++ b/Tasks/NuGetAuthenticateV1/task.loc.json @@ -54,7 +54,7 @@ }, "messages": { "Error_ServiceConnectionExists": "ms-resource:loc.messages.Error_ServiceConnectionExists", - "Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "Error_InvalidFeedUrl": "ms-resource:loc.messages.Error_InvalidFeedUrl", "Error_MissingFeedUrlOrServiceConnection": "ms-resource:loc.messages.Error_MissingFeedUrlOrServiceConnection", "Error_NuGetWithFeedUrlNotSupported": "ms-resource:loc.messages.Error_NuGetWithFeedUrlNotSupported", "Error_NuGetWithWIFNotSupported": "ms-resource:loc.messages.Error_NuGetWithWIFNotSupported", diff --git a/Tasks/NuGetAuthenticateV1/taskJsonOverride.json b/Tasks/NuGetAuthenticateV1/taskJsonOverride.json index 70b7badfec79..cd823903addb 100644 --- a/Tasks/NuGetAuthenticateV1/taskJsonOverride.json +++ b/Tasks/NuGetAuthenticateV1/taskJsonOverride.json @@ -10,15 +10,18 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "False" - } + }, + "visibleRule": "nuGetServiceConnections == ''" }, { "name": "feedUrl", + "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], "label": "Azure Artifacts URL", "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "type": "string", "defaultValue": "", - "required": false + "required": false, + "visibleRule": "workloadIdentityServiceConnection != ''" }, { "name": "forceReinstallCredentialProvider", @@ -36,7 +39,8 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - } + }, + "visibleRule": "workloadIdentityServiceConnection == ''" } ] } \ No newline at end of file diff --git a/Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json b/Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json index 8667786cb42c..238480ac57b6 100644 --- a/Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json +++ b/Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json @@ -10,15 +10,18 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "False" - } + }, + "visibleRule": "nuGetServiceConnections == ''" }, { "name": "feedUrl", + "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], "label": "ms-resource:loc.input.label.feedUrl", "helpMarkDown": "ms-resource:loc.input.help.feedUrl", "type": "string", "defaultValue": "", - "required": false + "required": false, + "visibleRule": "workloadIdentityServiceConnection != ''" }, { "name": "forceReinstallCredentialProvider", @@ -36,7 +39,8 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - } + }, + "visibleRule": "workloadIdentityServiceConnection == ''" } ] } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson b/_generated/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson index 65961b26b103..d21177e3f8dc 100644 --- a/_generated/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson +++ b/_generated/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson @@ -8,7 +8,7 @@ "loc.input.label.forceReinstallCredentialProvider": "Reinstall the credential provider even if already installed", "loc.input.help.forceReinstallCredentialProvider": "If the credential provider is already installed in the user profile, determines if it is overwritten with the task-provided credential provider. This may upgrade (or potentially downgrade) the credential provider.", "loc.messages.Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '%s' is not a valid Azure DevOps feed URL.", "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", "loc.messages.Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", "loc.messages.Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", diff --git a/_generated/NuGetAuthenticateV1/main.ts b/_generated/NuGetAuthenticateV1/main.ts index 697bed14f416..fa8d338a1347 100644 --- a/_generated/NuGetAuthenticateV1/main.ts +++ b/_generated/NuGetAuthenticateV1/main.ts @@ -17,9 +17,14 @@ async function main(): Promise { try { tl.setResourcePath(path.join(__dirname, 'task.json')); + // Install the credential provider + forceReinstallCredentialProvider = tl.getBoolInput("forceReinstallCredentialProvider", false); + await installCredProviderToUserProfile(forceReinstallCredentialProvider); - // Configure the credential provider for both same-organization feeds and service connections serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); + + + // Configure the credential provider for both same-organization feeds and service connections await configureCredProvider(ProtocolType.NuGet, serviceConnections); } catch (error) { tl.setResult(tl.TaskResult.Failed, error); @@ -28,7 +33,7 @@ async function main(): Promise { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, "isFeedUrlIncluded": !!tl.getInput("feedUrl"), - "isFeedUrlValid": validateFeedUrl(tl.getInput("feedUrl")), + "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")), "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, "isServiceConnectionIncluded": !!serviceConnections.length }); @@ -39,8 +44,13 @@ async function main(): Promise { * Validates that the feedUrl is a valid Azure DevOps feed URL. * Returns true if the feedUrl is valid, false otherwise. */ -function validateFeedUrl(feedUrl: string): boolean { - return !!feedUrl && /^https:\/\/(dev\.azure\.com|[\w-]+\.visualstudio\.com)\/[\w-]+\/_packaging\/[\w-]+\/nuget\/v3\/index\.json$/i.test(feedUrl); +function isValidFeed(feedUrl?: string | null): boolean { + if (!feedUrl) return false; + const normalized = feedUrl.trim().replace(/^[\u2018\u2019\u201C\u201D'"]|['"\u2018\u2019\u201C\u201D]$/g, ''); + + const feedRegex = /^https:\/\/(?:[\w.-]+\.)?(?:dev\.azure\.com|visualstudio\.com|vsts\.me|codedev\.ms|devppe\.azure\.com|codeapp\.ms)(?:\/[^\/]+(?:\/[^\/]+)?)?\/_packaging\/[^\/]+\/nuget\/v3\/index\.json\/?$/i; + + return feedRegex.test(normalized); } main(); diff --git a/_generated/NuGetAuthenticateV1/task.json b/_generated/NuGetAuthenticateV1/task.json index b73e6ec5b1d9..ce0405430d17 100644 --- a/_generated/NuGetAuthenticateV1/task.json +++ b/_generated/NuGetAuthenticateV1/task.json @@ -54,7 +54,7 @@ }, "messages": { "Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "Error_InvalidFeedUrl": "The provided feed URL '%s' is not a valid Azure DevOps feed URL.", "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", "Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", "Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", diff --git a/_generated/NuGetAuthenticateV1/taskJsonOverride.json b/_generated/NuGetAuthenticateV1/taskJsonOverride.json index 70b7badfec79..cd823903addb 100644 --- a/_generated/NuGetAuthenticateV1/taskJsonOverride.json +++ b/_generated/NuGetAuthenticateV1/taskJsonOverride.json @@ -10,15 +10,18 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "False" - } + }, + "visibleRule": "nuGetServiceConnections == ''" }, { "name": "feedUrl", + "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], "label": "Azure Artifacts URL", "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "type": "string", "defaultValue": "", - "required": false + "required": false, + "visibleRule": "workloadIdentityServiceConnection != ''" }, { "name": "forceReinstallCredentialProvider", @@ -36,7 +39,8 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - } + }, + "visibleRule": "workloadIdentityServiceConnection == ''" } ] } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1/taskJsonOverride.loc.json b/_generated/NuGetAuthenticateV1/taskJsonOverride.loc.json index 8667786cb42c..238480ac57b6 100644 --- a/_generated/NuGetAuthenticateV1/taskJsonOverride.loc.json +++ b/_generated/NuGetAuthenticateV1/taskJsonOverride.loc.json @@ -10,15 +10,18 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "False" - } + }, + "visibleRule": "nuGetServiceConnections == ''" }, { "name": "feedUrl", + "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], "label": "ms-resource:loc.input.label.feedUrl", "helpMarkDown": "ms-resource:loc.input.help.feedUrl", "type": "string", "defaultValue": "", - "required": false + "required": false, + "visibleRule": "workloadIdentityServiceConnection != ''" }, { "name": "forceReinstallCredentialProvider", @@ -36,7 +39,8 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - } + }, + "visibleRule": "workloadIdentityServiceConnection == ''" } ] } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson b/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson index d454e8b834a4..8adbd873282e 100644 --- a/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson +++ b/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson @@ -12,7 +12,7 @@ "loc.input.label.nuGetServiceConnections": "Service connection credentials for feeds outside this organization", "loc.input.help.nuGetServiceConnections": "Comma-separated list of NuGet service connection names for feeds outside this organization/collection. For feeds in this organization/collection, leave this blank; the build’s credentials are used automatically.", "loc.messages.Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "loc.messages.Error_InvalidFeedUrl": "The provided feed URL '%s' is not a valid Azure DevOps feed URL.", "loc.messages.Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", "loc.messages.Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", "loc.messages.Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", diff --git a/_generated/NuGetAuthenticateV1_Wif/main.ts b/_generated/NuGetAuthenticateV1_Wif/main.ts index ce28d596ea50..473580632b5b 100644 --- a/_generated/NuGetAuthenticateV1_Wif/main.ts +++ b/_generated/NuGetAuthenticateV1_Wif/main.ts @@ -18,36 +18,27 @@ async function main(): Promise { try { tl.setResourcePath(path.join(__dirname, 'task.json')); + // Install the credential provider + forceReinstallCredentialProvider = tl.getBoolInput("forceReinstallCredentialProvider", false); + await installCredProviderToUserProfile(forceReinstallCredentialProvider); - feedUrl = tl.getInput("feedUrl"); - entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); + entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); + feedUrl = tl.getInput("feedUrl", false); + // Failure case: User provides inputs for both NuGet & WIF Service Connections if (serviceConnections.length > 0 && entraWifServiceConnectionName) { tl.setResult(tl.TaskResult.Failed, tl.loc("Error_NuGetWithWIFNotSupported")); return; } - // Warning case: User provides feedUrl without providing a WIF service connection - // In the future, we will shift to breaking behavior - if (entraWifServiceConnectionName) { - // Happy path, continue with flow - } else if (feedUrl) { - tl.warning(tl.loc("Warn_IgnoringFeedUrl")); - feedUrl = null; - // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); - } - // Validate input is valid feed URL - if (feedUrl && !validateFeedUrl(feedUrl)) { + if (feedUrl && !isValidFeed(feedUrl)) { tl.setResult(tl.TaskResult.Failed, tl.loc("Error_InvalidFeedUrl", feedUrl)); + return; } - // Install the credential provider - forceReinstallCredentialProvider = tl.getBoolInput("forceReinstallCredentialProvider", false); - await installCredProviderToUserProfile(forceReinstallCredentialProvider); - // Only cross-org feedUrls are supported with Azure Devops service connections. If feedUrl is internal, the task will fail. if (entraWifServiceConnectionName && feedUrl ) { tl.debug(tl.loc("Info_AddingFederatedFeedAuth", entraWifServiceConnectionName, feedUrl)); @@ -56,16 +47,21 @@ async function main(): Promise { console.log(tl.loc("Info_SuccessAddingFederatedFeedAuth", feedUrl)); return; - } - // If the user doesn't provide a feedUrl, use the Azure Devops service connection to replace the Build Service - else if (entraWifServiceConnectionName && !feedUrl) { + } else if (entraWifServiceConnectionName && !feedUrl) { + // If the user doesn't provide a feedUrl, use the Azure Devops service connection to replace the Build Service configureCredProviderForSameOrganizationFeeds(ProtocolType.NuGet, entraWifServiceConnectionName); + return; - } + } else if (feedUrl) { + // Warning case: User provides feedUrl without providing a WIF service connection + // In the future, we will shift to breaking behavior + tl.warning(tl.loc("Warn_IgnoringFeedUrl")); + feedUrl = null; + // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); + } // Configure the credential provider for both same-organization feeds and service connections - serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); await configureCredProvider(ProtocolType.NuGet, serviceConnections); } catch (error) { tl.setResult(tl.TaskResult.Failed, error); @@ -74,7 +70,7 @@ async function main(): Promise { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, "isFeedUrlIncluded": !!tl.getInput("feedUrl"), - "isFeedUrlValid": validateFeedUrl(tl.getInput("feedUrl")), + "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")), "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, "isServiceConnectionIncluded": !!serviceConnections.length }); @@ -85,8 +81,13 @@ async function main(): Promise { * Validates that the feedUrl is a valid Azure DevOps feed URL. * Returns true if the feedUrl is valid, false otherwise. */ -function validateFeedUrl(feedUrl: string): boolean { - return !!feedUrl && /^https:\/\/(dev\.azure\.com|[\w-]+\.visualstudio\.com)\/[\w-]+\/_packaging\/[\w-]+\/nuget\/v3\/index\.json$/i.test(feedUrl); +function isValidFeed(feedUrl?: string | null): boolean { + if (!feedUrl) return false; + const normalized = feedUrl.trim().replace(/^[\u2018\u2019\u201C\u201D'"]|['"\u2018\u2019\u201C\u201D]$/g, ''); + + const feedRegex = /^https:\/\/(?:[\w.-]+\.)?(?:dev\.azure\.com|visualstudio\.com|vsts\.me|codedev\.ms|devppe\.azure\.com|codeapp\.ms)(?:\/[^\/]+(?:\/[^\/]+)?)?\/_packaging\/[^\/]+\/nuget\/v3\/index\.json\/?$/i; + + return feedRegex.test(normalized); } main(); diff --git a/_generated/NuGetAuthenticateV1_Wif/task.json b/_generated/NuGetAuthenticateV1_Wif/task.json index 20a197326a8f..df7ae30f7c8d 100644 --- a/_generated/NuGetAuthenticateV1_Wif/task.json +++ b/_generated/NuGetAuthenticateV1_Wif/task.json @@ -31,15 +31,20 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "False" - } + }, + "visibleRule": "nuGetServiceConnections == ''" }, { "name": "feedUrl", + "aliases": [ + "adoServiceConnectionCrossOrgFeedUrl" + ], "label": "Azure Artifacts URL", "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "type": "string", "defaultValue": "", - "required": false + "required": false, + "visibleRule": "workloadIdentityServiceConnection != ''" }, { "name": "forceReinstallCredentialProvider", @@ -57,7 +62,8 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - } + }, + "visibleRule": "workloadIdentityServiceConnection == ''" } ], "execution": { @@ -76,7 +82,7 @@ }, "messages": { "Error_ServiceConnectionExists": "An existing service connection already exists for the endpoint", - "Error_InvalidFeedUrl": "The provided feed URL '{0}' is not a valid Azure DevOps feed URL.", + "Error_InvalidFeedUrl": "The provided feed URL '%s' is not a valid Azure DevOps feed URL.", "Error_MissingFeedUrlOrServiceConnection": "Both feedUrl and azureDevOpsServiceConnection must be set together.", "Error_NuGetWithFeedUrlNotSupported": "Cannot specify both nuGetServiceConnections and feedUrl input parameters.", "Error_NuGetWithWIFNotSupported": "Cannot specify both nuGetServiceConnections and azureDevOpsServiceConnection(workloadIdentityServiceConnection) input parameters.", diff --git a/_generated/NuGetAuthenticateV1_Wif/task.loc.json b/_generated/NuGetAuthenticateV1_Wif/task.loc.json index a77c75f637a0..f657e4cdebe0 100644 --- a/_generated/NuGetAuthenticateV1_Wif/task.loc.json +++ b/_generated/NuGetAuthenticateV1_Wif/task.loc.json @@ -31,15 +31,20 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "False" - } + }, + "visibleRule": "nuGetServiceConnections == ''" }, { "name": "feedUrl", + "aliases": [ + "adoServiceConnectionCrossOrgFeedUrl" + ], "label": "ms-resource:loc.input.label.feedUrl", "helpMarkDown": "ms-resource:loc.input.help.feedUrl", "type": "string", "defaultValue": "", - "required": false + "required": false, + "visibleRule": "workloadIdentityServiceConnection != ''" }, { "name": "forceReinstallCredentialProvider", @@ -57,7 +62,8 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - } + }, + "visibleRule": "workloadIdentityServiceConnection == ''" } ], "execution": { diff --git a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json index 70b7badfec79..cd823903addb 100644 --- a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json +++ b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json @@ -10,15 +10,18 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "False" - } + }, + "visibleRule": "nuGetServiceConnections == ''" }, { "name": "feedUrl", + "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], "label": "Azure Artifacts URL", "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", "type": "string", "defaultValue": "", - "required": false + "required": false, + "visibleRule": "workloadIdentityServiceConnection != ''" }, { "name": "forceReinstallCredentialProvider", @@ -36,7 +39,8 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - } + }, + "visibleRule": "workloadIdentityServiceConnection == ''" } ] } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json index 8667786cb42c..238480ac57b6 100644 --- a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json +++ b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json @@ -10,15 +10,18 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "False" - } + }, + "visibleRule": "nuGetServiceConnections == ''" }, { "name": "feedUrl", + "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], "label": "ms-resource:loc.input.label.feedUrl", "helpMarkDown": "ms-resource:loc.input.help.feedUrl", "type": "string", "defaultValue": "", - "required": false + "required": false, + "visibleRule": "workloadIdentityServiceConnection != ''" }, { "name": "forceReinstallCredentialProvider", @@ -36,7 +39,8 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - } + }, + "visibleRule": "workloadIdentityServiceConnection == ''" } ] } \ No newline at end of file From 2dd7aceaf6508ff5e0b7ec6beb3bb788d1aeebe0 Mon Sep 17 00:00:00 2001 From: Alex Torres Date: Thu, 4 Sep 2025 15:25:24 -0700 Subject: [PATCH 5/6] Telemetry fix in non-wif, Update Input Var name, help prompt fix --- .../Strings/resources.resjson/en-US/resources.resjson | 2 +- Tasks/NuGetAuthenticateV1/main.ts | 11 +++++------ Tasks/NuGetAuthenticateV1/taskJsonOverride.json | 7 +++---- Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json | 5 ++--- _generated/NuGetAuthenticateV1/main.ts | 9 ++++----- _generated/NuGetAuthenticateV1/taskJsonOverride.json | 7 +++---- .../NuGetAuthenticateV1/taskJsonOverride.loc.json | 5 ++--- .../Strings/resources.resjson/en-US/resources.resjson | 2 +- _generated/NuGetAuthenticateV1_Wif/main.ts | 11 +++++------ _generated/NuGetAuthenticateV1_Wif/task.json | 7 +++---- _generated/NuGetAuthenticateV1_Wif/task.loc.json | 5 ++--- .../NuGetAuthenticateV1_Wif/taskJsonOverride.json | 7 +++---- .../NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json | 5 ++--- 13 files changed, 36 insertions(+), 47 deletions(-) diff --git a/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson b/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson index e9b8ceb3c868..3d8063587869 100644 --- a/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/NuGetAuthenticateV1/Strings/resources.resjson/en-US/resources.resjson @@ -7,7 +7,7 @@ "loc.input.help.nuGetServiceConnections": "Comma-separated list of NuGet service connection names for feeds outside this organization/collection. For feeds in this organization/collection, leave this blank; the build’s credentials are used automatically.", "loc.input.label.forceReinstallCredentialProvider": "Reinstall the credential provider even if already installed", "loc.input.help.forceReinstallCredentialProvider": "If the credential provider is already installed in the user profile, determines if it is overwritten with the task-provided credential provider. This may upgrade (or potentially downgrade) the credential provider.", - "loc.input.help.feedUrl": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "loc.input.help.feedUrl": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json", "loc.input.label.feedUrl": "Azure Artifacts URL", "loc.input.help.workloadIdentityServiceConnection": "If this is set, feedUrl is required. All other inputs are ignored.", "loc.input.label.workloadIdentityServiceConnection": "'Azure DevOps' Service Connection", diff --git a/Tasks/NuGetAuthenticateV1/main.ts b/Tasks/NuGetAuthenticateV1/main.ts index 5bef9ef031d9..8620c11eb6ff 100644 --- a/Tasks/NuGetAuthenticateV1/main.ts +++ b/Tasks/NuGetAuthenticateV1/main.ts @@ -7,7 +7,6 @@ import { installCredProviderToUserProfile, configureCredProvider, configureCredP import { ProtocolType } from 'azure-pipelines-tasks-artifacts-common/protocols'; import { getPackagingServiceConnections } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils' import { emitTelemetry } from 'azure-pipelines-tasks-artifacts-common/telemetry' -import { ServiceConnection } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils'; async function main(): Promise { let forceReinstallCredentialProvider = null; @@ -25,7 +24,6 @@ async function main(): Promise { await installCredProviderToUserProfile(forceReinstallCredentialProvider); serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); - #if WIF entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); feedUrl = tl.getInput("feedUrl", false); @@ -57,10 +55,10 @@ async function main(): Promise { return; } else if (feedUrl) { // Warning case: User provides feedUrl without providing a WIF service connection - // In the future, we will shift to breaking behavior tl.warning(tl.loc("Warn_IgnoringFeedUrl")); feedUrl = null; + // In the future, we will shift to breaking behavior // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); } #endif @@ -73,9 +71,10 @@ async function main(): Promise { emitTelemetry("Packaging", "NuGetAuthenticateV1", { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, - "isFeedUrlIncluded": !!tl.getInput("feedUrl"), - "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")), - "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, + // We have to check both input names because only WIF versions of the task are aware of aliases + "isFeedUrlIncluded": !!(tl.getInput("feedUrl") || tl.getInput("azureDevOpsServiceConnectionCrossOrgFeedUrl")), + "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")) || isValidFeed(tl.getInput("azureDevOpsServiceConnectionCrossOrgFeedUrl")), + "isEntraWifServiceConnectionNameIncluded": !!(tl.getInput("workloadIdentityServiceConnection")|| tl.getInput("azureDevOpsServiceConnection")), "isServiceConnectionIncluded": !!serviceConnections.length }); } diff --git a/Tasks/NuGetAuthenticateV1/taskJsonOverride.json b/Tasks/NuGetAuthenticateV1/taskJsonOverride.json index cd823903addb..234325ff52da 100644 --- a/Tasks/NuGetAuthenticateV1/taskJsonOverride.json +++ b/Tasks/NuGetAuthenticateV1/taskJsonOverride.json @@ -15,9 +15,9 @@ }, { "name": "feedUrl", - "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], + "aliases": ["azureDevOpsServiceConnectionCrossOrgFeedUrl"], "label": "Azure Artifacts URL", - "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json", "type": "string", "defaultValue": "", "required": false, @@ -39,8 +39,7 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - }, - "visibleRule": "workloadIdentityServiceConnection == ''" + } } ] } \ No newline at end of file diff --git a/Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json b/Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json index 238480ac57b6..11c5a07b05b5 100644 --- a/Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json +++ b/Tasks/NuGetAuthenticateV1/taskJsonOverride.loc.json @@ -15,7 +15,7 @@ }, { "name": "feedUrl", - "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], + "aliases": ["azureDevOpsServiceConnectionCrossOrgFeedUrl"], "label": "ms-resource:loc.input.label.feedUrl", "helpMarkDown": "ms-resource:loc.input.help.feedUrl", "type": "string", @@ -39,8 +39,7 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - }, - "visibleRule": "workloadIdentityServiceConnection == ''" + } } ] } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1/main.ts b/_generated/NuGetAuthenticateV1/main.ts index fa8d338a1347..2cf33d7c3dd4 100644 --- a/_generated/NuGetAuthenticateV1/main.ts +++ b/_generated/NuGetAuthenticateV1/main.ts @@ -4,7 +4,6 @@ import { installCredProviderToUserProfile, configureCredProvider, configureCredP import { ProtocolType } from 'azure-pipelines-tasks-artifacts-common/protocols'; import { getPackagingServiceConnections } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils' import { emitTelemetry } from 'azure-pipelines-tasks-artifacts-common/telemetry' -import { ServiceConnection } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils'; async function main(): Promise { let forceReinstallCredentialProvider = null; @@ -23,7 +22,6 @@ async function main(): Promise { serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); - // Configure the credential provider for both same-organization feeds and service connections await configureCredProvider(ProtocolType.NuGet, serviceConnections); } catch (error) { @@ -32,9 +30,10 @@ async function main(): Promise { emitTelemetry("Packaging", "NuGetAuthenticateV1", { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, - "isFeedUrlIncluded": !!tl.getInput("feedUrl"), - "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")), - "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, + // We have to check both input names because only WIF versions of the task are aware of aliases + "isFeedUrlIncluded": !!(tl.getInput("feedUrl") || tl.getInput("azureDevOpsServiceConnectionCrossOrgFeedUrl")), + "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")) || isValidFeed(tl.getInput("azureDevOpsServiceConnectionCrossOrgFeedUrl")), + "isEntraWifServiceConnectionNameIncluded": !!(tl.getInput("workloadIdentityServiceConnection")|| tl.getInput("azureDevOpsServiceConnection")), "isServiceConnectionIncluded": !!serviceConnections.length }); } diff --git a/_generated/NuGetAuthenticateV1/taskJsonOverride.json b/_generated/NuGetAuthenticateV1/taskJsonOverride.json index cd823903addb..234325ff52da 100644 --- a/_generated/NuGetAuthenticateV1/taskJsonOverride.json +++ b/_generated/NuGetAuthenticateV1/taskJsonOverride.json @@ -15,9 +15,9 @@ }, { "name": "feedUrl", - "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], + "aliases": ["azureDevOpsServiceConnectionCrossOrgFeedUrl"], "label": "Azure Artifacts URL", - "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json", "type": "string", "defaultValue": "", "required": false, @@ -39,8 +39,7 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - }, - "visibleRule": "workloadIdentityServiceConnection == ''" + } } ] } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1/taskJsonOverride.loc.json b/_generated/NuGetAuthenticateV1/taskJsonOverride.loc.json index 238480ac57b6..11c5a07b05b5 100644 --- a/_generated/NuGetAuthenticateV1/taskJsonOverride.loc.json +++ b/_generated/NuGetAuthenticateV1/taskJsonOverride.loc.json @@ -15,7 +15,7 @@ }, { "name": "feedUrl", - "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], + "aliases": ["azureDevOpsServiceConnectionCrossOrgFeedUrl"], "label": "ms-resource:loc.input.label.feedUrl", "helpMarkDown": "ms-resource:loc.input.help.feedUrl", "type": "string", @@ -39,8 +39,7 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - }, - "visibleRule": "workloadIdentityServiceConnection == ''" + } } ] } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson b/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson index 8adbd873282e..a0c75befbf46 100644 --- a/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson +++ b/_generated/NuGetAuthenticateV1_Wif/Strings/resources.resjson/en-US/resources.resjson @@ -6,7 +6,7 @@ "loc.input.label.workloadIdentityServiceConnection": "'Azure DevOps' Service Connection", "loc.input.help.workloadIdentityServiceConnection": "If this is set, feedUrl is required. All other inputs are ignored.", "loc.input.label.feedUrl": "Azure Artifacts URL", - "loc.input.help.feedUrl": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "loc.input.help.feedUrl": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json", "loc.input.label.forceReinstallCredentialProvider": "Reinstall the credential provider even if already installed", "loc.input.help.forceReinstallCredentialProvider": "If the credential provider is already installed in the user profile, determines if it is overwritten with the task-provided credential provider. This may upgrade (or potentially downgrade) the credential provider.", "loc.input.label.nuGetServiceConnections": "Service connection credentials for feeds outside this organization", diff --git a/_generated/NuGetAuthenticateV1_Wif/main.ts b/_generated/NuGetAuthenticateV1_Wif/main.ts index 473580632b5b..517fa6f75aef 100644 --- a/_generated/NuGetAuthenticateV1_Wif/main.ts +++ b/_generated/NuGetAuthenticateV1_Wif/main.ts @@ -5,7 +5,6 @@ import { installCredProviderToUserProfile, configureCredProvider, configureCredP import { ProtocolType } from 'azure-pipelines-tasks-artifacts-common/protocols'; import { getPackagingServiceConnections } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils' import { emitTelemetry } from 'azure-pipelines-tasks-artifacts-common/telemetry' -import { ServiceConnection } from 'azure-pipelines-tasks-artifacts-common/serviceConnectionUtils'; async function main(): Promise { let forceReinstallCredentialProvider = null; @@ -23,7 +22,6 @@ async function main(): Promise { await installCredProviderToUserProfile(forceReinstallCredentialProvider); serviceConnections = getPackagingServiceConnections('nuGetServiceConnections'); - entraWifServiceConnectionName = tl.getInput("workloadIdentityServiceConnection"); feedUrl = tl.getInput("feedUrl", false); @@ -54,10 +52,10 @@ async function main(): Promise { return; } else if (feedUrl) { // Warning case: User provides feedUrl without providing a WIF service connection - // In the future, we will shift to breaking behavior tl.warning(tl.loc("Warn_IgnoringFeedUrl")); feedUrl = null; + // In the future, we will shift to breaking behavior // tl.setResult(tl.TaskResult.SucceededWithIssues, tl.loc("Error_NuGetWithFeedUrlNotSupported")); } @@ -69,9 +67,10 @@ async function main(): Promise { emitTelemetry("Packaging", "NuGetAuthenticateV1", { 'NuGetAuthenticate.ForceReinstallCredentialProvider': forceReinstallCredentialProvider, "FederatedFeedAuthCount": federatedFeedAuthSuccessCount, - "isFeedUrlIncluded": !!tl.getInput("feedUrl"), - "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")), - "isEntraWifServiceConnectionNameIncluded": !!entraWifServiceConnectionName, + // We have to check both input names because only WIF versions of the task are aware of aliases + "isFeedUrlIncluded": !!(tl.getInput("feedUrl") || tl.getInput("azureDevOpsServiceConnectionCrossOrgFeedUrl")), + "isFeedUrlValid": isValidFeed(tl.getInput("feedUrl")) || isValidFeed(tl.getInput("azureDevOpsServiceConnectionCrossOrgFeedUrl")), + "isEntraWifServiceConnectionNameIncluded": !!(tl.getInput("workloadIdentityServiceConnection")|| tl.getInput("azureDevOpsServiceConnection")), "isServiceConnectionIncluded": !!serviceConnections.length }); } diff --git a/_generated/NuGetAuthenticateV1_Wif/task.json b/_generated/NuGetAuthenticateV1_Wif/task.json index df7ae30f7c8d..b77347ad0415 100644 --- a/_generated/NuGetAuthenticateV1_Wif/task.json +++ b/_generated/NuGetAuthenticateV1_Wif/task.json @@ -37,10 +37,10 @@ { "name": "feedUrl", "aliases": [ - "adoServiceConnectionCrossOrgFeedUrl" + "azureDevOpsServiceConnectionCrossOrgFeedUrl" ], "label": "Azure Artifacts URL", - "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json", "type": "string", "defaultValue": "", "required": false, @@ -62,8 +62,7 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - }, - "visibleRule": "workloadIdentityServiceConnection == ''" + } } ], "execution": { diff --git a/_generated/NuGetAuthenticateV1_Wif/task.loc.json b/_generated/NuGetAuthenticateV1_Wif/task.loc.json index f657e4cdebe0..cd83a4f26c76 100644 --- a/_generated/NuGetAuthenticateV1_Wif/task.loc.json +++ b/_generated/NuGetAuthenticateV1_Wif/task.loc.json @@ -37,7 +37,7 @@ { "name": "feedUrl", "aliases": [ - "adoServiceConnectionCrossOrgFeedUrl" + "azureDevOpsServiceConnectionCrossOrgFeedUrl" ], "label": "ms-resource:loc.input.label.feedUrl", "helpMarkDown": "ms-resource:loc.input.help.feedUrl", @@ -62,8 +62,7 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - }, - "visibleRule": "workloadIdentityServiceConnection == ''" + } } ], "execution": { diff --git a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json index cd823903addb..234325ff52da 100644 --- a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json +++ b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.json @@ -15,9 +15,9 @@ }, { "name": "feedUrl", - "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], + "aliases": ["azureDevOpsServiceConnectionCrossOrgFeedUrl"], "label": "Azure Artifacts URL", - "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json/", + "helpMarkDown": "If this is set, azureDevOpsServiceConnection is required. All other inputs are ignored. Not compatible with nuGetServiceConnections. Feed Url should be in the NuGet service index format, e.g. https://pkgs.dev.azure.com/{ORG_NAME}/{PROJECT}/_packaging/{FEED_NAME}/nuget/v3/index.json", "type": "string", "defaultValue": "", "required": false, @@ -39,8 +39,7 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - }, - "visibleRule": "workloadIdentityServiceConnection == ''" + } } ] } \ No newline at end of file diff --git a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json index 238480ac57b6..11c5a07b05b5 100644 --- a/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json +++ b/_generated/NuGetAuthenticateV1_Wif/taskJsonOverride.loc.json @@ -15,7 +15,7 @@ }, { "name": "feedUrl", - "aliases": ["adoServiceConnectionCrossOrgFeedUrl"], + "aliases": ["azureDevOpsServiceConnectionCrossOrgFeedUrl"], "label": "ms-resource:loc.input.label.feedUrl", "helpMarkDown": "ms-resource:loc.input.help.feedUrl", "type": "string", @@ -39,8 +39,7 @@ "properties": { "EditableOptions": "False", "MultiSelectFlatList": "True" - }, - "visibleRule": "workloadIdentityServiceConnection == ''" + } } ] } \ No newline at end of file From cf8ec14ee8e726382fd46f24bef467c6ff914245 Mon Sep 17 00:00:00 2001 From: Alex Torres Date: Thu, 4 Sep 2025 15:39:17 -0700 Subject: [PATCH 6/6] rebuild --- _generated/NuGetAuthenticateV1.versionmap.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_generated/NuGetAuthenticateV1.versionmap.txt b/_generated/NuGetAuthenticateV1.versionmap.txt index 32de7561bcfd..209d7a74fc76 100644 --- a/_generated/NuGetAuthenticateV1.versionmap.txt +++ b/_generated/NuGetAuthenticateV1.versionmap.txt @@ -1,2 +1,2 @@ Default|1.263.0 -wif_242|1.263.1 \ No newline at end of file +wif_242|1.263.1