Skip to content

Integrate AzArtifacts Credential Provider #1765

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

Open
wants to merge 92 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
3dbb6c7
Add azartifacts credential provider integration
alerickson Dec 18, 2024
6d52514
Add dynamic parameters to Register-PSResourceRepository and Set-PSRes…
alerickson Dec 18, 2024
fe270a1
Bug fixes and clean up
alerickson Dec 19, 2024
a99b2b2
Add tests
alerickson Dec 19, 2024
fc81545
Update AdoV2 server tests
alerickson Dec 19, 2024
7f5f0ae
Add logging for GH pkgs tests
alerickson Dec 19, 2024
01ab760
Remove GH pkgs logging
alerickson Dec 19, 2024
43a69e7
Rename tests
alerickson Dec 19, 2024
bfeb5e0
Add Verbose messaging
alerickson Dec 23, 2024
2644183
Update dynamic parameters for Set and Register repositories
alerickson Dec 24, 2024
b11eb71
Dynamic param should not appear when using Repositories param set, co…
alerickson Dec 24, 2024
d3154ed
Set dynamic param updates
alerickson Dec 24, 2024
317463d
Add -CredentialProvider None to existing ADO tests
alerickson Dec 26, 2024
e063a97
uncomment cred provider tests
alerickson Dec 26, 2024
ae5a467
Update ADO feed
alerickson Jan 3, 2025
f994d14
Fix #1777: Fixes bug with nuspec dependency version range when versio…
Jan 24, 2025
1cfdf2a
only convert Version info to hashtable if its not an empty string
anamnavi Mar 4, 2025
f3fe35e
delete unzippedPath in test after it's written to or subsequent Expan…
anamnavi Mar 4, 2025
97ef9d7
Update Dependency parsing logic to account for Az packages with Az* n…
anamnavi Feb 12, 2025
b1ba2b2
specify Azpreview explicitly in condition
anamnavi Feb 12, 2025
d189750
add test for Azpreview from MAR
anamnavi Feb 12, 2025
35bce61
fix test for Azpreview from MAR
anamnavi Feb 12, 2025
74abeb0
update outdated az FindName() from MAR test
anamnavi Feb 12, 2025
79f1e23
check if version is greaterthan not equal
anamnavi Feb 12, 2025
25bee9d
Allow wildcard for MAR repository for FindAll and FindByName (#1786)
adityapatwardhan Feb 19, 2025
ffa42a9
Use authentication challenge for unauthenticated container registry r…
adityapatwardhan Feb 21, 2025
405a0f7
Use deploybox to release to Gallery (#1800)
adityapatwardhan Feb 26, 2025
8a3c89c
Get metadata properties when finding a PSResource from a ContainerReg…
anamnavi Feb 25, 2025
4a60d68
Retrieve Tags property which can be in PrivateData.PSData but is not …
anamnavi Feb 25, 2025
e27c8c3
clean up code
anamnavi Feb 25, 2025
6af54e1
check privateData JsonElement kind, if Object check for its propertie…
anamnavi Feb 25, 2025
8050006
fix install for a package from MAR that may have different version th…
anamnavi Feb 18, 2025
5a3cca2
add find and install tests for 2 digit pkg
anamnavi Feb 18, 2025
0e77d20
add -TrustRepository to install tests
anamnavi Feb 18, 2025
96f76e7
account for prerelease version when using manifest version
anamnavi Feb 18, 2025
dd142a9
add test for preview install
anamnavi Feb 18, 2025
ec8d2cc
fix error in test logic
anamnavi Feb 18, 2025
5645a14
account for 2 digit version being concatenated with prerelease when c…
anamnavi Feb 25, 2025
5add5e5
Update README.md
alerickson Feb 20, 2025
7ac9a55
Update changelog, release notes, version for v1.1.1 release (#1801)
anamnavi Mar 6, 2025
24047d7
Update .NET to 8.0.406 (#1802)
adityapatwardhan Mar 6, 2025
3b34f53
Remove InstallationPath to Install .NET Dependencies task (#1804)
anamnavi Mar 7, 2025
1a043eb
Update NuGet assembly versions (#1807)
adityapatwardhan Mar 24, 2025
8290e62
Add CODEOWNERS file (#1818)
anamnavi Apr 30, 2025
71110ba
Add SupportsWildcards attribute to Repository parameter of Install-PS…
sdwheeler May 7, 2025
36acf3c
Fix PSResourceGet CI for ContainerRegistry (#1829)
adityapatwardhan Jun 17, 2025
a6e71fa
Fix catalog access for Container Registry repositories (#1831)
adityapatwardhan Jun 18, 2025
d48a2d5
Remove netstandard2.0 from build options (#1835)
alerickson Jun 23, 2025
adac2bf
NuGet v3 populate dependencies (#1778)
o-l-a-v Jun 24, 2025
ef6e17d
Update changelog, release notes and version (#1838)
alerickson Jun 26, 2025
068493f
Add azartifacts credential provider integration
alerickson Dec 18, 2024
bc4fbdb
Add dynamic parameters to Register-PSResourceRepository and Set-PSRes…
alerickson Dec 18, 2024
1f0c768
Bug fixes and clean up
alerickson Dec 19, 2024
2446093
Add tests
alerickson Dec 19, 2024
3128532
Update AdoV2 server tests
alerickson Dec 19, 2024
adfd8d7
Add logging for GH pkgs tests
alerickson Dec 19, 2024
f83e9f8
Remove GH pkgs logging
alerickson Dec 19, 2024
603a04a
Rename tests
alerickson Dec 19, 2024
b93be9b
Add Verbose messaging
alerickson Dec 23, 2024
9410ba5
Update dynamic parameters for Set and Register repositories
alerickson Dec 24, 2024
d2099ec
Dynamic param should not appear when using Repositories param set, co…
alerickson Dec 24, 2024
f9e3253
Set dynamic param updates
alerickson Dec 24, 2024
ca9e36e
Add -CredentialProvider None to existing ADO tests
alerickson Dec 26, 2024
5be8a6d
uncomment cred provider tests
alerickson Dec 26, 2024
0a19373
Update ADO feed
alerickson Jan 3, 2025
b178031
Merge branch 'addAdoCredProvider' of https://github.com/alerickson/PS…
alerickson Jun 30, 2025
8436ac4
Install cred provider and setup secret in test CI
alerickson Jul 8, 2025
f001264
Merge branch 'master' into addAdoCredProvider
alerickson Jul 8, 2025
992af99
Add capture environment
alerickson Jul 9, 2025
fc5a264
Merge branch 'addAdoCredProvider' of https://github.com/powershell/PS…
alerickson Jul 9, 2025
bfcdc9a
Update endpoint variable for setting creds
alerickson Jul 9, 2025
4634617
Update repo uri variable value
alerickson Jul 9, 2025
324ab1b
add logging
alerickson Jul 9, 2025
1ae81db
Try adding username to endpoints value
alerickson Jul 9, 2025
c8d01ee
add logging
alerickson Jul 9, 2025
dd32cd8
check if env is set for tests
alerickson Jul 9, 2025
4c71f1d
See if new env var is accessible
alerickson Jul 9, 2025
d1ff4fa
Add double quotations
alerickson Jul 9, 2025
b82a714
change var to here string
alerickson Jul 10, 2025
19f2e59
change variable contents
alerickson Jul 10, 2025
a9ac2aa
remove username
alerickson Jul 10, 2025
11657ad
Add endpoint obj as json
alerickson Jul 10, 2025
1ae884b
second try
alerickson Jul 10, 2025
04066df
Add verbose logging
adityapatwardhan Jul 10, 2025
f0f5c27
Convert from secure string
adityapatwardhan Jul 10, 2025
bfba721
Fix typo
adityapatwardhan Jul 10, 2025
904bd28
fix tests
alerickson Jul 10, 2025
b8ff08d
test new module
alerickson Jul 10, 2025
ee6efce
add debugging
alerickson Jul 11, 2025
928f7a5
revert test changes
alerickson Jul 11, 2025
f293c9e
fix dynamic parameter and add test
alerickson Jul 11, 2025
b9deb95
Add test
alerickson Jul 11, 2025
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
36 changes: 36 additions & 0 deletions .ci/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ jobs:
displayName: Install Secret store
condition: eq(${{ parameters.useAzAuth }}, false)

- task: NuGetAuthenticate@1
displayName: Install Azure Artifacts Credential Provider
inputs:
forceReinstallCredentialProvider: true

- task: DownloadBuildArtifacts@0
displayName: 'Download artifacts'
inputs:
Expand Down Expand Up @@ -63,6 +68,37 @@ jobs:
displayName: Install module for test from downloaded artifact
workingDirectory: ${{ parameters.buildDirectory }}

- task: AzurePowerShell@5
inputs:
azureSubscription: PSResourceGetACR
azurePowerShellVersion: LatestVersion
ScriptType: InlineScript
pwsh: true
inline: |
Write-Verbose -Verbose "Setting up secret for Azure Artifacts Credential Provider"
$azt = (Get-AzAccessToken).Token | ConvertFrom-SecureString -AsPlainText

Write-Verbose -Verbose "Setting up Azure Artifacts Credential Provider secret - token - $azt"

$ADORepoName = "psrg-credprovidertest"
$ADORepoUri = "https://pkgs.dev.azure.com/powershell-rel/PSResourceGet/_packaging/psrg-credprovidertest/nuget/v2"

$endpointCredsObj = @{ endpointCredentials = @( @{ endpoint = $ADoRepoURI; password = $azt })}
$VSS_NUGET_EXTERNAL_FEED_ENDPOINTS = $endpointCredsObj | ConvertTo-Json -Compress

Write-Verbose -Verbose "Setting VSS_NUGET_EXTERNAL_FEED_ENDPOINTS environment variable $VSS_NUGET_EXTERNAL_FEED_ENDPOINTS"

$vstsCommandString = "vso[task.setvariable variable=VSS_NUGET_EXTERNAL_FEED_ENDPOINTS]$VSS_NUGET_EXTERNAL_FEED_ENDPOINTS"
Write-Host "sending " + $vstsCommandString
Write-Host "##$vstsCommandString"

displayName: 'Setup Azure Artifacts Credential Provider secret'
condition: eq(${{ parameters.useAzAuth }}, false)

- pwsh: |
Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose
displayName: Capture environment

- task: AzurePowerShell@5
inputs:
azureSubscription: PSResourceGetACR
Expand Down
301 changes: 301 additions & 0 deletions src/code/CredentialProvider.cs

Large diffs are not rendered by default.

35 changes: 32 additions & 3 deletions src/code/FindHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,16 @@ public IEnumerable<PSResourceInfo> FindByResourceName(
}

repositoryNamesToSearch.Add(currentRepository.Name);
_networkCredential = Utils.SetNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);

// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (currentRepository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}
else {
_networkCredential = Utils.SetSecretManagementNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}

ServerApiCall currentServer = ServerFactory.GetServer(currentRepository, _cmdletPassedIn, _networkCredential);
if (currentServer == null)
{
Expand Down Expand Up @@ -387,7 +396,17 @@ public IEnumerable<PSCommandResourceInfo> FindByCommandOrDscResource(
}

repositoryNamesToSearch.Add(currentRepository.Name);
_networkCredential = Utils.SetNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);

// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (currentRepository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}
else
{
_networkCredential = Utils.SetSecretManagementNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}

ServerApiCall currentServer = ServerFactory.GetServer(currentRepository, _cmdletPassedIn, _networkCredential);
if (currentServer == null)
{
Expand Down Expand Up @@ -591,7 +610,17 @@ public IEnumerable<PSResourceInfo> FindByTag(
}

repositoryNamesToSearch.Add(currentRepository.Name);
_networkCredential = Utils.SetNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);

// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (currentRepository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}
else
{
_networkCredential = Utils.SetSecretManagementNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}

ServerApiCall currentServer = ServerFactory.GetServer(currentRepository, _cmdletPassedIn, _networkCredential);
if (currentServer == null)
{
Expand Down
64 changes: 10 additions & 54 deletions src/code/InstallHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,16 @@ private List<PSResourceInfo> ProcessRepositories(
string repoName = currentRepository.Name;
sourceTrusted = currentRepository.Trusted || trustRepository;

_networkCredential = Utils.SetNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (currentRepository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}
else
{
_networkCredential = Utils.SetSecretManagementNetworkCredential(currentRepository, _networkCredential, _cmdletPassedIn);
}

ServerApiCall currentServer = ServerFactory.GetServer(currentRepository, _cmdletPassedIn, _networkCredential);

if (currentServer == null)
Expand Down Expand Up @@ -353,59 +362,6 @@ private List<PSResourceInfo> ProcessRepositories(
return allPkgsInstalled;
}

/// <summary>
/// Checks if any of the package versions are already installed and if they are removes them from the list of packages to install.
/// </summary>
private List<PSResourceInfo> FilterByInstalledPkgs(List<PSResourceInfo> packages)
{
// Package install paths.
// _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable).
// _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations.
// e.g.:
// ./InstallPackagePath1/PackageA
// ./InstallPackagePath1/PackageB
// ./InstallPackagePath2/PackageC
// ./InstallPackagePath3/PackageD

_cmdletPassedIn.WriteDebug("In InstallHelper::FilterByInstalledPkgs()");
// Get currently installed packages.
var getHelper = new GetHelper(_cmdletPassedIn);
var installedPackageNames = new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
foreach (var installedPkg in getHelper.GetInstalledPackages(
pkgs: packages,
pathsToSearch: _pathsToSearch))
{
installedPackageNames.Add(installedPkg.Name);
}

if (installedPackageNames.Count is 0)
{
return packages;
}

// Return only packages that are not already installed.
var filteredPackages = new List<PSResourceInfo>();
foreach (var pkg in packages)
{
if (!installedPackageNames.Contains(pkg.Name))
{
// Add packages that still need to be installed.
filteredPackages.Add(pkg);
}
else
{
// Remove from tracking list of packages to install.
pkg.AdditionalMetadata.TryGetValue("NormalizedVersion", out string normalizedVersion);
_cmdletPassedIn.WriteWarning($"Resource '{pkg.Name}' with version '{normalizedVersion}' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter");

// Remove from tracking list of packages to install.
_pkgNamesToInstall.RemoveAll(x => x.Equals(pkg.Name, StringComparison.InvariantCultureIgnoreCase));
}
}

return filteredPackages;
}

/// <summary>
/// Deletes temp directory and is called at end of install process.
/// </summary>
Expand Down
40 changes: 18 additions & 22 deletions src/code/PSRepositoryInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,74 +27,70 @@ public enum APIVersion
ContainerRegistry
}

public enum CredentialProviderType
{
None,
AzArtifacts
}

#endregion

#region Constructor

public PSRepositoryInfo(string name, Uri uri, int priority, bool trusted, PSCredentialInfo credentialInfo, APIVersion apiVersion, bool allowed)
public PSRepositoryInfo(string name, Uri uri, int priority, bool trusted, PSCredentialInfo credentialInfo, CredentialProviderType credentialProvider, APIVersion apiVersion, bool allowed)
{
Name = name;
Uri = uri;
Priority = priority;
Trusted = trusted;
CredentialInfo = credentialInfo;
CredentialProvider = credentialProvider;
ApiVersion = apiVersion;
IsAllowedByPolicy = allowed;
}

#endregion

#region Enum

public enum RepositoryProviderType
{
None,
ACR,
AzureDevOps
}

#endregion

#region Properties

/// <summary>
/// the Name of the repository
/// The Name of the repository.
/// </summary>
public string Name { get; }

/// <summary>
/// the Uri for the repository
/// The Uri for the repository.
/// </summary>
public Uri Uri { get; }

/// <summary>
/// whether the repository is trusted
/// Whether the repository is trusted.
/// </summary>
public bool Trusted { get; }

/// <summary>
/// the priority of the repository
/// The priority of the repository.
/// </summary>
[ValidateRange(0, 100)]
public int Priority { get; }

/// <summary>
/// the type of repository provider (eg, AzureDevOps, ContainerRegistry, etc.)
/// The credential information for repository authentication.
/// </summary>
public RepositoryProviderType RepositoryProvider { get; }
public PSCredentialInfo CredentialInfo { get; set; }

/// <summary>
/// the credential information for repository authentication
/// Specifies which credential provider to use.
/// </summary>
public PSCredentialInfo CredentialInfo { get; }
public CredentialProviderType CredentialProvider { get; set; }

/// <summary>
/// the API protocol version for the repository
/// The API protocol version for the repository.
/// </summary>
public APIVersion ApiVersion { get; }

// <summary>
/// is it allowed by policy
/// Specifies whether the repository is allowed by policy.
/// </summary>
public bool IsAllowedByPolicy { get; set; }

Expand Down
10 changes: 9 additions & 1 deletion src/code/PublishHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,15 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe
return;
}

_networkCredential = Utils.SetNetworkCredential(repository, _networkCredential, _cmdletPassedIn);
// Set network credentials via passed in credentials, AzArtifacts CredentialProvider, or SecretManagement.
if (repository.CredentialProvider.Equals(PSRepositoryInfo.CredentialProviderType.AzArtifacts))
{
_networkCredential = Utils.SetCredentialProviderNetworkCredential(repository, _networkCredential, _cmdletPassedIn);
}
else
{
_networkCredential = Utils.SetSecretManagementNetworkCredential(repository, _networkCredential, _cmdletPassedIn);
}

// Check if dependencies already exist within the repo if:
// 1) the resource to publish has dependencies and
Expand Down
Loading
Loading