Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions src/Sign.Cli/AzureCredentialOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ namespace Sign.Cli
{
internal sealed class AzureCredentialOptions
{
internal Option<string?> CredentialTypeOption = new Option<string?>(["--azure-credential-type", "-act"], Resources.CredentialTypeOptionDescription).FromAmong(
AzureCredentialType.AzureCli,
AzureCredentialType.AzurePowerShell,
AzureCredentialType.ManagedIdentity,
AzureCredentialType.WorkloadIdentity);
internal Option<string?> ManagedIdentityClientIdOption = new(["--managed-identity-client-id", "-mici"], Resources.ManagedIdentityClientIdOptionDescription);
internal Option<string?> ManagedIdentityResourceIdOption = new(["--managed-identity-resource-id", "-miri"], Resources.ManagedIdentityResourceIdOptionDescription);
internal Option<bool?> ObsoleteManagedIdentityOption { get; } = new(["--azure-key-vault-managed-identity", "-kvm"], Resources.ManagedIdentityOptionDescription) { IsHidden = true };
Expand All @@ -22,6 +27,7 @@ internal sealed class AzureCredentialOptions

internal void AddOptionsToCommand(Command command)
{
command.AddOption(CredentialTypeOption);
command.AddOption(ManagedIdentityClientIdOption);
command.AddOption(ManagedIdentityResourceIdOption);
command.AddOption(ObsoleteManagedIdentityOption);
Expand Down Expand Up @@ -70,10 +76,38 @@ internal DefaultAzureCredentialOptions CreateDefaultAzureCredentialOptions(Parse
return new ClientSecretCredential(tenantId, clientId, secret);
}

DefaultAzureCredentialOptions options = CreateDefaultAzureCredentialOptions(context.ParseResult);
switch (context.ParseResult.GetValueForOption(CredentialTypeOption))
{
case AzureCredentialType.AzureCli:
return new AzureCliCredential();

case AzureCredentialType.AzurePowerShell:
return new AzurePowerShellCredential();

case AzureCredentialType.ManagedIdentity:
string? managedIdentityClientId = context.ParseResult.GetValueForOption(ManagedIdentityClientIdOption);
if (managedIdentityClientId is not null)
{
return new ManagedIdentityCredential(managedIdentityClientId);
}

string? managedIdentityResourceId = context.ParseResult.GetValueForOption(ManagedIdentityResourceIdOption);
if (managedIdentityResourceId is not null)
{
return new ManagedIdentityCredential(new ResourceIdentifier(managedIdentityResourceId));
}

// CodeQL [SM05137] Sign CLI is not a production service.
return new DefaultAzureCredential(options);
return new ManagedIdentityCredential();

case AzureCredentialType.WorkloadIdentity:
return new WorkloadIdentityCredential();

default:
DefaultAzureCredentialOptions options = CreateDefaultAzureCredentialOptions(context.ParseResult);

// CodeQL [SM05137] Sign CLI is not a production service.
return new DefaultAzureCredential(options);
}
}
}
}
14 changes: 14 additions & 0 deletions src/Sign.Cli/AzureCredentialType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE.txt file in the project root for more information.

namespace Sign.Cli
{
internal static class AzureCredentialType
{
public const string AzureCli = "azure-cli";
public const string AzurePowerShell = "azure-powershell";
public const string ManagedIdentity = "managed-identity";
public const string WorkloadIdentity = "workload-identity";
}
}
9 changes: 9 additions & 0 deletions src/Sign.Cli/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Sign.Cli/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,7 @@
<value>Warning: The Microsoft Visual C++ 14 runtime is required but was not detected on your system. Download and install from https://aka.ms/vs/17/release/vc_redist.x64.exe</value>
<comment>{Locked="https://aka.ms/vs/17/release/vc_redist.x64.exe"} is a URL.</comment>
</data>
<data name="CredentialTypeOptionDescription" xml:space="preserve">
<value>Azure credential type that will be used. This defaults to DefaultAzureCredential.</value>
</data>
</root>
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">Podepisovat binární soubory a kontejnery.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">Popis podpisového certifikátu.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">Signieren Sie Binärdateien und Container.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">Beschreibung des Signaturzertifikats.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">Firmar archivos binarios y contenedores.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">Descripción del certificado de firma.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">Signer les fichiers binaires et les conteneurs.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">Description du certificat de signature.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">Consente di firmare file binari e contenitori.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">Descrizione del certificato di firma.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">バイナリとコンテナーに署名します。</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">署名証明書の説明。</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">이진 파일 및 컨테이너에 서명합니다.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">서명 인증서에 대한 설명입니다.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">Podpisz pliki binarne i kontenery.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">Opis certyfikatu podpisywania.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">Autenticar contêineres e binários.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">Descrição do certificado de autenticação.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.ru.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">Подписывание двоичных файлов и контейнеров.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">Описание сертификата для подписи</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.tr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">İkili dosyaları ve kapsayıcıları imzalayın.</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">İmzalama sertifikasının açıklaması.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.zh-Hans.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">对二进制文件和容器进行签名。</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">签名证书的说明。</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Sign.Cli/xlf/Resources.zh-Hant.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<target state="translated">簽署二進位檔和容器。</target>
<note />
</trans-unit>
<trans-unit id="CredentialTypeOptionDescription">
<source>Azure credential type that will be used. This defaults to DefaultAzureCredential.</source>
<target state="new">Azure credential type that will be used. This defaults to DefaultAzureCredential.</target>
<note />
</trans-unit>
<trans-unit id="DescriptionOptionDescription">
<source>Description of the signing certificate.</source>
<target state="translated">簽署憑證的描述。</target>
Expand Down
94 changes: 94 additions & 0 deletions test/Sign.Cli.Test/AzureCredentialOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Completions;
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using Azure.Core;
using Azure.Identity;
using Moq;
using Sign.Core;
Expand All @@ -24,6 +27,30 @@ public AzureCredentialOptionsTests()
_options = _command.AzureCredentialOptions;
}

[Fact]
public void CredentialTypeOption_Always_HasArityOfExactlyOne()
{
Assert.Equal(ArgumentArity.ExactlyOne, _options.CredentialTypeOption.Arity);
}

[Fact]
public void CredentialTypeOption_Always_IsNotRequired()
{
Assert.False(_options.CredentialTypeOption.IsRequired);
}

[Fact]
public void CredentialTypeOption_Always_HasCorrectCompletions()
{
CompletionItem[] completions = [.. _options.CredentialTypeOption.GetCompletions()];

Assert.Equal(4, completions.Length);
Assert.Equal("azure-cli", completions[0].Label);
Assert.Equal("azure-powershell", completions[1].Label);
Assert.Equal("managed-identity", completions[2].Label);
Assert.Equal("workload-identity", completions[3].Label);
}

[Fact]
public void ManagedIdentityClientIdOption_Always_HasArityOfExactlyOne()
{
Expand Down Expand Up @@ -127,6 +154,7 @@ public void AddOptionsToCommand_Always_AddsAllOptionsToCommand()

_options.AddOptionsToCommand(command);

Assert.Contains(_options.CredentialTypeOption, command.Options);
Assert.Contains(_options.ManagedIdentityClientIdOption, command.Options);
Assert.Contains(_options.ManagedIdentityResourceIdOption, command.Options);
Assert.Contains(_options.ObsoleteManagedIdentityOption, command.Options);
Expand Down Expand Up @@ -172,5 +200,71 @@ public void CreateDefaultAzureCredentialOptions_WhenNoOptionsAreSpecified_Exclud
Assert.False(credentialOptions.ExcludeVisualStudioCredential);
Assert.False(credentialOptions.ExcludeWorkloadIdentityCredential);
}

[Fact]
public void CreateTokenCredential_WhenClientSecretOptionsAreSet_ReturnsClientSecretCredential()
{
ParseResult result = _parser.Parse("azure-key-vault -kvu https://keyvault.test -kvc a -kvt b -kvi c -kvs d e");
InvocationContext invocationContext = new(result);

TokenCredential? tokenCredential = _options.CreateTokenCredential(invocationContext);

Assert.IsType<ClientSecretCredential>(tokenCredential);
}

[Fact]
public void CreateTokenCredential_WhenCredentialTypeIsAzureCli_ReturnsAzureCliCredential()
{
ParseResult result = _parser.Parse("azure-key-vault -kvu https://keyvault.test -kvc a -act azure-cli b");
InvocationContext invocationContext = new(result);

TokenCredential? tokenCredential = _options.CreateTokenCredential(invocationContext);

Assert.IsType<AzureCliCredential>(tokenCredential);
}

[Fact]
public void CreateTokenCredential_WhenCredentialTypeIsAzurePowerShell_ReturnsAzurePowerShellCredential()
{
ParseResult result = _parser.Parse("azure-key-vault -kvu https://keyvault.test -kvc a -act azure-powershell b");
InvocationContext invocationContext = new(result);

TokenCredential? tokenCredential = _options.CreateTokenCredential(invocationContext);

Assert.IsType<AzurePowerShellCredential>(tokenCredential);
}

[Fact]
public void CreateTokenCredential_WhenCredentialTypeIsManagedIdentity_ReturnsManagedIdentityCredential()
{
ParseResult result = _parser.Parse("azure-key-vault -kvu https://keyvault.test -kvc a -act managed-identity b");
InvocationContext invocationContext = new(result);

TokenCredential? tokenCredential = _options.CreateTokenCredential(invocationContext);

Assert.IsType<ManagedIdentityCredential>(tokenCredential);
}

[Fact]
public void CreateTokenCredential_WhenCredentialTypeIsWorkloadIdentity_ReturnsWorkloadIdentityCredential()
{
ParseResult result = _parser.Parse("azure-key-vault -kvu https://keyvault.test -kvc a -act workload-identity b");
InvocationContext invocationContext = new(result);

TokenCredential? tokenCredential = _options.CreateTokenCredential(invocationContext);

Assert.IsType<WorkloadIdentityCredential>(tokenCredential);
}

[Fact]
public void CreateTokenCredential_WhenCredentialTypeIsNotSet_ReturnsDefaultAzureCredential()
{
ParseResult result = _parser.Parse("azure-key-vault -kvu https://keyvault.test -kvc a b");
InvocationContext invocationContext = new(result);

TokenCredential? tokenCredential = _options.CreateTokenCredential(invocationContext);

Assert.IsType<DefaultAzureCredential>(tokenCredential);
}
}
}