Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Service connections for push #19585

Merged
merged 27 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4311c6e
UPack allow push with service con
AlexVTor Feb 27, 2024
f90c302
NuGet Command allow push with service connection
AlexVTor Feb 27, 2024
7013090
NpmV1 allow push with service connection
AlexVTor Feb 27, 2024
49bd5b5
DotNetCore allow service connections for push
AlexVTor Feb 27, 2024
ea6a1a2
update task.lock.json
AlexVTor Feb 27, 2024
67c8bff
Adding Generated files UniversalPackages
AlexVTor Feb 27, 2024
7173ee0
Adding Generated files DotNetCoreCLIV2
AlexVTor Feb 27, 2024
2caaf70
Adding Generated files NuGetCommandV2
AlexVTor Feb 27, 2024
ad82f4d
Adding Generated files NpmV1
AlexVTor Feb 27, 2024
1384283
Merge branch 'master' into users/alextorres/AllowServiceConnectionsFo…
AlexVTor Feb 27, 2024
4e726fb
npm task fix
Feb 27, 2024
a0ff3d1
fixing build breaks
Feb 27, 2024
6d7580b
Merge branch 'master' into users/alextorres/AllowServiceConnectionsFo…
AlexVTor Feb 28, 2024
dec56aa
removed unused var
AlexVTor Feb 28, 2024
13c87ca
Localized and improved warning messages Upack
AlexVTor Feb 28, 2024
b32cb66
Localized and improved warning messages Npm
AlexVTor Feb 28, 2024
ae7fb57
Localized and improved warning messages NuGet
AlexVTor Feb 28, 2024
515a84f
Localized and improved warning messages DotNet
AlexVTor Feb 28, 2024
6cfa3a5
Merge branch 'master' into users/alextorres/AllowServiceConnectionsFo…
AlexVTor Feb 28, 2024
5cc472a
bumping upack task version
Feb 28, 2024
2c399fb
Building npmV1 with node 16
AlexVTor Feb 28, 2024
b684091
Revert "Building npmV1 with node 16"
AlexVTor Feb 28, 2024
7a16c03
updating task.loc.json
AlexVTor Feb 28, 2024
7114750
Adding string to resources.rejson
AlexVTor Feb 28, 2024
567ebf8
updating resources string nuget
AlexVTor Feb 28, 2024
9a67059
updating resources strings dotnet upack
AlexVTor Feb 28, 2024
7f16e70
forgot a comma
AlexVTor Feb 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 62 additions & 1 deletion Tasks/DotNetCoreCLIV2/pushcommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import * as ngRunner from 'azure-pipelines-tasks-packaging-common/nuget/NuGetToo
import * as pkgLocationUtils from 'azure-pipelines-tasks-packaging-common/locationUtilities';
import { getProjectAndFeedIdFromInputParam, logError } from 'azure-pipelines-tasks-packaging-common/util';

interface EndpointCredentials {
endpoint: string;
username?: string;
password: string;
}

export async function run(): Promise<void> {
let packagingLocation: pkgLocationUtils.PackagingLocation;
try {
Expand Down Expand Up @@ -65,8 +71,9 @@ export async function run(): Promise<void> {
}

// Setting up auth info
const accessToken = pkgLocationUtils.getSystemAccessToken();
let accessToken;
const isInternalFeed: boolean = nugetFeedType === 'internal';
accessToken = getAccessToken(isInternalFeed);
const internalAuthInfo = new auth.InternalAuthInfo(urlPrefixes, accessToken, /*useCredProvider*/ null, true);

let configFile = null;
Expand Down Expand Up @@ -182,3 +189,57 @@ function dotNetNuGetPushAsync(dotnetPath: string, packageFile: string, feedUri:
const envWithProxy = ngRunner.setNuGetProxyEnvironment(process.env, /*configFile*/ null, feedUri);
return dotnet.exec({ cwd: workingDirectory, env: envWithProxy } as IExecOptions);
}

function getAccessToken(isInternalFeed: boolean): string{
let accessToken: string;
let allowServiceConnection = tl.getVariable('PUBLISH_VIA_SERVICE_CONNECTION');

if(allowServiceConnection) {
let endpoint = tl.getInput('externalEndpoint', false);

if(endpoint && isInternalFeed === true) {
tl.debug("Found external endpoint, will use token for auth");
let endpointAuth = tl.getEndpointAuthorization(endpoint, true);
let endpointScheme = tl.getEndpointAuthorizationScheme(endpoint, true).toLowerCase();
switch(endpointScheme)
{
case ("token"):
accessToken = endpointAuth.parameters["apitoken"];
break;
default:
tl.warning(tl.loc("Warning_UnsupportedServiceConnectionAuth"));
break;
}
}
if(!accessToken && isInternalFeed === true)
{
tl.debug("Checking for auth from Cred Provider.");
const feed = getProjectAndFeedIdFromInputParam('feedPublish');
const JsonEndpointsString = process.env["VSS_NUGET_EXTERNAL_FEED_ENDPOINTS"];
if (JsonEndpointsString) {
tl.debug(`Endpoints found: ${JsonEndpointsString}`);

let endpointsArray: { endpointCredentials: EndpointCredentials[] } = JSON.parse(JsonEndpointsString);
tl.debug(`Feed details ${feed.feedId} ${feed.projectId}`);

for (let endpoint_in = 0; endpoint_in < endpointsArray.endpointCredentials.length; endpoint_in++) {
if (endpointsArray.endpointCredentials[endpoint_in].endpoint.search(feed.feedName) != -1) {
tl.debug(`Endpoint Credentials found for ${feed.feedName}`);
accessToken = endpointsArray.endpointCredentials[endpoint_in].password;
break;
}
}
}
}
if(!accessToken)
{
tl.debug('Defaulting to use the System Access Token.');
accessToken = pkgLocationUtils.getSystemAccessToken();
}
}
else {
accessToken = pkgLocationUtils.getSystemAccessToken();
}

return accessToken;
}
5 changes: 3 additions & 2 deletions Tasks/DotNetCoreCLIV2/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"demands": [],
"version": {
"Major": 2,
"Minor": 235,
"Minor": 236,
"Patch": 0
},
"minimumAgentVersion": "2.144.0",
Expand Down Expand Up @@ -579,6 +579,7 @@
"Net5NugetVersionCompat": ".NET 5 has some compatibility issues with older Nuget versions(<=5.7), so if you are using an older Nuget version(and not dotnet cli) to restore, then the dotnet cli commands (e.g. dotnet build) which rely on such restored packages might fail. To mitigate such error, you can either: (1) - Use dotnet cli to restore, (2) - Use Nuget version 5.8 to restore, (3) - Use global.json using an older sdk version(<=3) to build",
"DeprecatedDotnet2_2_And_3_0": "Info: .NET Core SDK/runtime 2.2 and 3.0 are now End of Life(EOL) and have been removed from all hosted agents. If you're using these SDK/runtimes on hosted agents, kindly upgrade to newer versions which are not EOL, or else use UseDotNet task to install the required version.",
"Warning_IncludeNuGetOrgEnabled": "IncludeNugetOrg is currently enabled for this task. To resolve this warning, edit your build task and set 'includeNuGetOrg' to 'false' or deselect 'Use packages from NuGet.org'.",
"Error_IncludeNuGetOrgEnabled": "Packages failed to restore. Edit your build task and set 'includeNuGetOrg' to 'false' or deselect 'Use packages from NuGet.org'."
"Error_IncludeNuGetOrgEnabled": "Packages failed to restore. Edit your build task and set 'includeNuGetOrg' to 'false' or deselect 'Use packages from NuGet.org'.",
"Warning_UnsupportedServiceConnectionAuth" : "The service connection does not use a supported authentication method. Please use a service connection with personal access token based auth."
}
}
2 changes: 1 addition & 1 deletion Tasks/DotNetCoreCLIV2/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"demands": [],
"version": {
"Major": 2,
"Minor": 235,
"Minor": 236,
"Patch": 0
},
"minimumAgentVersion": "2.144.0",
Expand Down
72 changes: 68 additions & 4 deletions Tasks/NpmV1/npmpublish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { INpmRegistry, NpmRegistry } from 'azure-pipelines-tasks-packaging-commo
import { NpmToolRunner } from './npmtoolrunner';
import * as util from 'azure-pipelines-tasks-packaging-common/util';
import * as npmutil from 'azure-pipelines-tasks-packaging-common/npm/npmutil';
import { PackagingLocation } from 'azure-pipelines-tasks-packaging-common/locationUtilities';
import * as npmrcparser from 'azure-pipelines-tasks-packaging-common/npm/npmrcparser';
import { getSystemAccessToken, PackagingLocation, getFeedRegistryUrl, RegistryType } from 'azure-pipelines-tasks-packaging-common/locationUtilities';
import * as os from 'os';

export async function run(packagingLocation: PackagingLocation): Promise<void> {
const workingDir = tl.getInput(NpmTaskInput.WorkingDir) || process.cwd();
Expand Down Expand Up @@ -33,10 +35,9 @@ export async function getPublishRegistry(packagingLocation: PackagingLocation):
case RegistryLocation.Feed:
tl.debug(tl.loc('PublishFeed'));
const feed = util.getProjectAndFeedIdFromInputParam(NpmTaskInput.PublishFeed);
npmRegistry = await NpmRegistry.FromFeedId(
npmRegistry = await getNpmRegistry(
packagingLocation.DefaultPackagingUri,
feed.feedId,
feed.projectId,
feed,
false /* authOnly */,
true /* useSession */);
break;
Expand All @@ -47,4 +48,67 @@ export async function getPublishRegistry(packagingLocation: PackagingLocation):
break;
}
return npmRegistry;
}

async function getNpmRegistry(defaultPackagingUri: string, feed: any, authOnly?: boolean, useSession?: boolean) {
AlexVTor marked this conversation as resolved.
Show resolved Hide resolved
const lineEnd = os.EOL;
let url: string;
let nerfed: string;
let auth: string;
let username: string;
let email: string;
let password64: string;

url = npmrcparser.NormalizeRegistry( await getFeedRegistryUrl(defaultPackagingUri, RegistryType.npm, feed.feedId, feed.projectId, null, useSession));
nerfed = util.toNerfDart(url);

// Setting up auth info
const accessToken = getAccessToken();

// Azure DevOps does not support PATs+Bearer only JWTs+Bearer
email = 'VssEmail';
username = 'VssToken';
password64 = Buffer.from(accessToken).toString('base64');
tl.setSecret(password64);

auth = nerfed + ':username=' + username + lineEnd;
auth += nerfed + ':_password=' + password64 + lineEnd;
auth += nerfed + ':email=' + email + lineEnd;

return new NpmRegistry(url, auth, authOnly);
}

function getAccessToken(): string {
let accessToken: string;
let allowServiceConnection = tl.getVariable('PUBLISH_VIA_SERVICE_CONNECTION');

if(allowServiceConnection) {
let endpoint = tl.getInput('publishEndpoint', false);

if(endpoint) {
tl.debug("Found external endpoint, will use token for auth");
let endpointAuth = tl.getEndpointAuthorization(endpoint, true);
let endpointScheme = tl.getEndpointAuthorizationScheme(endpoint, true).toLowerCase();
switch(endpointScheme)
{
case ("token"):
accessToken = endpointAuth.parameters["apitoken"];
break;
default:
tl.warning(tl.loc("UnsupportedServiceConnectionAuth"));
break;
}
}
if(!accessToken)
{
tl.debug('Defaulting to use the System Access Token.');
accessToken = getSystemAccessToken();
}
return accessToken;
}
else{
accessToken = getSystemAccessToken();
}

return accessToken;
}
6 changes: 4 additions & 2 deletions Tasks/NpmV1/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 1,
"Minor": 231,
"Minor": 236,
"Patch": 0
},
"runsOn": [
Expand Down Expand Up @@ -204,6 +204,8 @@
"OverridingProjectNpmrc": "Overriding project .npmrc: %s",
"RestoringProjectNpmrc": "Restoring project .npmrc",
"WorkingDirectoryNotDirectory": "Please change your working directory to a valid directory",
"NGCommon_AreaNotFoundInSps": "Unable to locate the '%s' [%s] area. The service containing that area may not be available in your region."
"NGCommon_AreaNotFoundInSps": "Unable to locate the '%s' [%s] area. The service containing that area may not be available in your region.",
"UnsupportedServiceConnectionAuth" : "The service connection does not use a supported authentication method. Please use a service connection with personal access token based auth."

}
}
2 changes: 1 addition & 1 deletion Tasks/NpmV1/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 1,
"Minor": 231,
"Minor": 236,
"Patch": 0
},
"runsOn": [
Expand Down
66 changes: 64 additions & 2 deletions Tasks/NuGetCommandV2/nugetpublisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ interface IVstsNuGetPushOptions {
settings: vstsNuGetPushToolRunner.VstsNuGetPushSettings;
}

interface EndpointCredentials {
endpoint: string;
username?: string;
password: string;
}

export async function run(nuGetPath: string): Promise<void> {
let packagingLocation: pkgLocationUtils.PackagingLocation;
try {
Expand Down Expand Up @@ -103,7 +109,10 @@ export async function run(nuGetPath: string): Promise<void> {
}

// Setting up auth info
const accessToken = pkgLocationUtils.getSystemAccessToken();
let accessToken;
let feed;
const isInternalFeed: boolean = nugetFeedType === "internal";
accessToken = getAccessToken(isInternalFeed);
const quirks = await ngToolRunner.getNuGetQuirksAsync(nuGetPath);

// Clauses ordered in this way to avoid short-circuit evaluation, so the debug info printed by the functions
Expand Down Expand Up @@ -131,7 +140,6 @@ export async function run(nuGetPath: string): Promise<void> {
let credCleanup = () => { return; };

let feedUri: string;
const isInternalFeed: boolean = nugetFeedType === "internal";

let authInfo: auth.NuGetExtendedAuthInfo;
let nuGetConfigHelper: NuGetConfigHelper2;
Expand Down Expand Up @@ -405,3 +413,57 @@ function shouldUseVstsNuGetPush(isInternalFeed: boolean, conflictsAllowed: boole

return false;
}

function getAccessToken(isInternalFeed: boolean): string{
let accessToken: string;
let allowServiceConnection = tl.getVariable('PUBLISH_VIA_SERVICE_CONNECTION');

if(allowServiceConnection) {
let endpoint = tl.getInput('externalEndpoint', false);

if(endpoint && isInternalFeed === true) {
tl.debug("Found external endpoint, will use token for auth");
let endpointAuth = tl.getEndpointAuthorization(endpoint, true);
let endpointScheme = tl.getEndpointAuthorizationScheme(endpoint, true).toLowerCase();
switch(endpointScheme)
{
case ("token"):
accessToken = endpointAuth.parameters["apitoken"];
break;
default:
tl.warning(tl.loc("Warning_UnsupportedServiceConnectionAuth"));
break;
}
}
if(!accessToken && isInternalFeed === true)
{
tl.debug("Checking for auth from Cred Provider.");
const feed = getProjectAndFeedIdFromInputParam('feedPublish');
const JsonEndpointsString = process.env["VSS_NUGET_EXTERNAL_FEED_ENDPOINTS"];
if (JsonEndpointsString) {
tl.debug(`Endpoints found: ${JsonEndpointsString}`);

let endpointsArray: { endpointCredentials: EndpointCredentials[] } = JSON.parse(JsonEndpointsString);
tl.debug(`Feed details ${feed.feedId} ${feed.projectId}`);

for (let endpoint_in = 0; endpoint_in < endpointsArray.endpointCredentials.length; endpoint_in++) {
if (endpointsArray.endpointCredentials[endpoint_in].endpoint.search(feed.feedName) != -1) {
tl.debug(`Endpoint Credentials found for ${feed.feedName}`);
accessToken = endpointsArray.endpointCredentials[endpoint_in].password;
break;
}
}
}
}
if(!accessToken)
{
tl.debug('Defaulting to use the System Access Token.');
accessToken = pkgLocationUtils.getSystemAccessToken();
}
}
else {
accessToken = pkgLocationUtils.getSystemAccessToken();
}

return accessToken;
}
5 changes: 3 additions & 2 deletions Tasks/NuGetCommandV2/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 231,
"Minor": 236,
"Patch": 0
},
"runsOn": [
Expand Down Expand Up @@ -542,6 +542,7 @@
"Warning_UpdatingNuGetVersion": "Updating version of NuGet.exe to %s from %s. Behavior changes or breaking changes might occur as NuGet updates to a new version. If this is not desired, deselect the 'Check for Latest Version' option in the task.",
"Error_NugetFailedWithCodeAndErr": "The nuget command failed with exit code(%s) and error(%s)",
"Warning_IncludeNuGetOrgEnabled": "IncludeNugetOrg is currently enabled for this task. To resolve this warning, edit your build task and set 'includeNuGetOrg' to 'false' or deselect 'Use packages from NuGet.org'.",
"Error_IncludeNuGetOrgEnabled": "Packages failed to restore. Edit your build task and set 'includeNuGetOrg' to 'false' or deselect 'Use packages from NuGet.org'."
"Error_IncludeNuGetOrgEnabled": "Packages failed to restore. Edit your build task and set 'includeNuGetOrg' to 'false' or deselect 'Use packages from NuGet.org'.",
"Warning_UnsupportedServiceConnectionAuth" : "The service connection does not use a supported authentication method. Please use a service connection with personal access token based auth."
}
}
2 changes: 1 addition & 1 deletion Tasks/NuGetCommandV2/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 231,
"Minor": 236,
"Patch": 0
},
"runsOn": [
Expand Down
3 changes: 2 additions & 1 deletion Tasks/UniversalPackagesV0/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@
"Warn_CredentialsNotFound": "Could not determine credentials to use for Universal Packages",
"Warning_SessionCreationFailed": "Could not create provenance session: %s",
"Error_UniversalPackagesNotSupportedOnPrem": "Universal Packages are not supported in Azure DevOps Server.",
"Error_ProcessorArchitectureNotSupported": "Universal Packages require an x64 agent."
"Error_ProcessorArchitectureNotSupported": "Universal Packages require an x64 agent.",
"Warning_UnsupportedServiceConnectionAuth" : "The service connection does not use a supported authentication method. Please use a service connection with personal access token based auth."
}
}
Loading
Loading