diff --git a/src/Sign.Cli/Sign.Cli.csproj b/src/Sign.Cli/Sign.Cli.csproj
index d5b1a9f1..8c34c446 100644
--- a/src/Sign.Cli/Sign.Cli.csproj
+++ b/src/Sign.Cli/Sign.Cli.csproj
@@ -22,6 +22,7 @@
+
@@ -68,6 +69,11 @@
TrueResources.resx
+
+ True
+ True
+ TrustedSigningResources.resx
+
@@ -83,5 +89,9 @@
ResXFileCodeGeneratorResources.Designer.cs
+
+ ResXFileCodeGenerator
+ TrustedSigningResources.Designer.cs
+
-
\ No newline at end of file
+
diff --git a/src/Sign.Cli/SignCommand.cs b/src/Sign.Cli/SignCommand.cs
index ab7d8706..dc54a0a7 100644
--- a/src/Sign.Cli/SignCommand.cs
+++ b/src/Sign.Cli/SignCommand.cs
@@ -23,11 +23,17 @@ internal SignCommand(IServiceProviderFactory? serviceProviderFactory = null)
codeCommand.AddCommand(azureKeyVaultCommand);
- CertificateStoreCommand certManagerCommand = new(
+ CertificateStoreCommand certificateStoreCommand = new(
codeCommand,
serviceProviderFactory);
- codeCommand.AddCommand(certManagerCommand);
+ codeCommand.AddCommand(certificateStoreCommand);
+
+ TrustedSigningCommand trustedSigningCommand = new(
+ codeCommand,
+ serviceProviderFactory);
+
+ codeCommand.AddCommand(trustedSigningCommand);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Sign.Cli/TrustedSigningCommand.cs b/src/Sign.Cli/TrustedSigningCommand.cs
new file mode 100644
index 00000000..a32cef77
--- /dev/null
+++ b/src/Sign.Cli/TrustedSigningCommand.cs
@@ -0,0 +1,100 @@
+// 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.
+
+using System.CommandLine;
+using System.CommandLine.Invocation;
+using System.CommandLine.IO;
+using Azure.Core;
+using Azure.Identity;
+using Sign.Core;
+using Sign.SignatureProviders.TrustedSigning;
+
+namespace Sign.Cli
+{
+ internal sealed class TrustedSigningCommand : Command
+ {
+ internal Option EndpointOption { get; } = new(["-tse", "--trusted-signing-endpoint"], TrustedSigningResources.EndpointOptionDescription);
+ internal Option AccountOption { get; } = new(["-tsa", "--trusted-signing-account"], TrustedSigningResources.AccountOptionDescription);
+ internal Option CertificateProfileOption { get; } = new(["-tsc", "--trusted-signing-certificate-profile"], TrustedSigningResources.CertificateProfileOptionDescription);
+ internal Option ManagedIdentityOption { get; } = new(["-tsm", "--trusted-signing-managed-identity"], getDefaultValue: () => false, TrustedSigningResources.ManagedIdentityOptionDescription);
+ internal Option TenantIdOption { get; } = new(["-tst", "--trusted-signing-tenant-id"], TrustedSigningResources.TenantIdOptionDescription);
+ internal Option ClientIdOption { get; } = new(["-tsi", "--trusted-signing-client-id"], TrustedSigningResources.ClientIdOptionDescription);
+ internal Option ClientSecretOption { get; } = new(["-tss", "--trusted-signing-client-secret"], TrustedSigningResources.ClientSecretOptionDescription);
+
+ internal Argument FileArgument { get; } = new("file(s)", Resources.FilesArgumentDescription);
+
+ internal TrustedSigningCommand(CodeCommand codeCommand, IServiceProviderFactory serviceProviderFactory)
+ : base("trusted-signing", TrustedSigningResources.CommandDescription)
+ {
+ ArgumentNullException.ThrowIfNull(codeCommand, nameof(codeCommand));
+ ArgumentNullException.ThrowIfNull(serviceProviderFactory, nameof(serviceProviderFactory));
+
+ EndpointOption.IsRequired = true;
+ AccountOption.IsRequired = true;
+ CertificateProfileOption.IsRequired = true;
+
+ AddOption(EndpointOption);
+ AddOption(AccountOption);
+ AddOption(CertificateProfileOption);
+ AddOption(ManagedIdentityOption);
+ AddOption(TenantIdOption);
+ AddOption(ClientIdOption);
+ AddOption(ClientSecretOption);
+
+ AddArgument(FileArgument);
+
+ this.SetHandler(async (InvocationContext context) =>
+ {
+ string? fileArgument = context.ParseResult.GetValueForArgument(FileArgument);
+
+ if (string.IsNullOrEmpty(fileArgument))
+ {
+ context.Console.Error.WriteLine(Resources.MissingFileValue);
+ context.ExitCode = ExitCode.InvalidOptions;
+ return;
+ }
+
+ bool useManagedIdentity = context.ParseResult.GetValueForOption(ManagedIdentityOption);
+
+ TokenCredential? credential = null;
+
+ if (useManagedIdentity)
+ {
+ credential = new DefaultAzureCredential();
+ }
+ else
+ {
+ string? tenantId = context.ParseResult.GetValueForOption(TenantIdOption);
+ string? clientId = context.ParseResult.GetValueForOption(ClientIdOption);
+ string? clientSecret = context.ParseResult.GetValueForOption(ClientSecretOption);
+
+ if (string.IsNullOrEmpty(tenantId) ||
+ string.IsNullOrEmpty(clientId) ||
+ string.IsNullOrEmpty(clientSecret))
+ {
+ context.Console.Error.WriteFormattedLine(
+ TrustedSigningResources.InvalidClientSecretCredential,
+ TenantIdOption,
+ ClientIdOption,
+ ClientSecretOption);
+ context.ExitCode = ExitCode.NoInputsFound;
+ return;
+ }
+
+ credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
+ }
+
+ // Some of the options are required and that is why we can safely use
+ // the null-forgiving operator (!) to simplify the code.
+ Uri endpointUrl = context.ParseResult.GetValueForOption(EndpointOption)!;
+ string accountName = context.ParseResult.GetValueForOption(AccountOption)!;
+ string certificateProfileName = context.ParseResult.GetValueForOption(CertificateProfileOption)!;
+
+ TrustedSigningServiceProvider trustedSigningServiceProvider = new(credential, endpointUrl, accountName, certificateProfileName);
+
+ await codeCommand.HandleAsync(context, serviceProviderFactory, trustedSigningServiceProvider, fileArgument);
+ });
+ }
+ }
+}
diff --git a/src/Sign.Cli/TrustedSigningResources.Designer.cs b/src/Sign.Cli/TrustedSigningResources.Designer.cs
new file mode 100644
index 00000000..bb83ef8d
--- /dev/null
+++ b/src/Sign.Cli/TrustedSigningResources.Designer.cs
@@ -0,0 +1,144 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Sign.Cli {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class TrustedSigningResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal TrustedSigningResources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Sign.Cli.TrustedSigningResources", typeof(TrustedSigningResources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The Trusted Signing Account name..
+ ///
+ internal static string AccountOptionDescription {
+ get {
+ return ResourceManager.GetString("AccountOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The Certificate Profile name..
+ ///
+ internal static string CertificateProfileOptionDescription {
+ get {
+ return ResourceManager.GetString("CertificateProfileOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Client ID to authenticate to Trusted Signing..
+ ///
+ internal static string ClientIdOptionDescription {
+ get {
+ return ResourceManager.GetString("ClientIdOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Client secret to authenticate to Trusted Signing..
+ ///
+ internal static string ClientSecretOptionDescription {
+ get {
+ return ResourceManager.GetString("ClientSecretOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Use Trusted Signing.
+ ///
+ internal static string CommandDescription {
+ get {
+ return ResourceManager.GetString("CommandDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources..
+ ///
+ internal static string EndpointOptionDescription {
+ get {
+ return ResourceManager.GetString("EndpointOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to If not using a managed identity, all of these options are required: {0}, {1}, and {2}..
+ ///
+ internal static string InvalidClientSecretCredential {
+ get {
+ return ResourceManager.GetString("InvalidClientSecretCredential", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Managed identity to authenticate to Trusted Signing..
+ ///
+ internal static string ManagedIdentityOptionDescription {
+ get {
+ return ResourceManager.GetString("ManagedIdentityOptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Tenant ID to authenticate to Trusted Signing..
+ ///
+ internal static string TenantIdOptionDescription {
+ get {
+ return ResourceManager.GetString("TenantIdOptionDescription", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/Sign.Cli/TrustedSigningResources.resx b/src/Sign.Cli/TrustedSigningResources.resx
new file mode 100644
index 00000000..c561010d
--- /dev/null
+++ b/src/Sign.Cli/TrustedSigningResources.resx
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ The Trusted Signing Account name.
+
+
+ The Certificate Profile name.
+
+
+ Client ID to authenticate to Trusted Signing.
+
+
+ Client secret to authenticate to Trusted Signing.
+
+
+ Use Trusted Signing
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+
+
+ Tenant ID to authenticate to Trusted Signing.
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.cs.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.cs.xlf
new file mode 100644
index 00000000..60055953
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.cs.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.de.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.de.xlf
new file mode 100644
index 00000000..b509a8ee
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.de.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.es.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.es.xlf
new file mode 100644
index 00000000..6c3ee824
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.es.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.fr.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.fr.xlf
new file mode 100644
index 00000000..e7ab7de6
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.fr.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.it.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.it.xlf
new file mode 100644
index 00000000..9cc34f71
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.it.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.ja.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.ja.xlf
new file mode 100644
index 00000000..b350db7a
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.ja.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.ko.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.ko.xlf
new file mode 100644
index 00000000..6d1e1b17
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.ko.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.pl.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.pl.xlf
new file mode 100644
index 00000000..f70d470f
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.pl.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.pt-BR.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.pt-BR.xlf
new file mode 100644
index 00000000..c8382898
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.pt-BR.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.ru.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.ru.xlf
new file mode 100644
index 00000000..d770d712
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.ru.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.tr.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.tr.xlf
new file mode 100644
index 00000000..08e308eb
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.tr.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.zh-Hans.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.zh-Hans.xlf
new file mode 100644
index 00000000..9ae6cda8
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.zh-Hans.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Sign.Cli/xlf/TrustedSigningResources.zh-Hant.xlf b/src/Sign.Cli/xlf/TrustedSigningResources.zh-Hant.xlf
new file mode 100644
index 00000000..4451f442
--- /dev/null
+++ b/src/Sign.Cli/xlf/TrustedSigningResources.zh-Hant.xlf
@@ -0,0 +1,52 @@
+
+
+
+
+
+ The Trusted Signing Account name.
+ The Trusted Signing Account name.
+
+
+
+ The Certificate Profile name.
+ The Certificate Profile name.
+
+
+
+ Client ID to authenticate to Trusted Signing.
+ Client ID to authenticate to Trusted Signing.
+
+
+
+ Client secret to authenticate to Trusted Signing.
+ Client secret to authenticate to Trusted Signing.
+
+
+
+ Use Trusted Signing
+ Use Trusted Signing
+
+
+
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+ The Trusted Signing Account endpoint. The URI value must have a URI that aligns to the region your Trusted Signing Account and Certificate Profile you are specifying were created in during the setup of these resources.
+
+
+
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ If not using a managed identity, all of these options are required: {0}, {1}, and {2}.
+ {NumberedPlaceholder="{0}", "{1}", "{2}"} are option names and should not be localized.
+
+
+ Managed identity to authenticate to Trusted Signing.
+ Managed identity to authenticate to Trusted Signing.
+
+
+
+ Tenant ID to authenticate to Trusted Signing.
+ Tenant ID to authenticate to Trusted Signing.
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Sign.Cli.Test/TrustedSigningCommandTests.cs b/test/Sign.Cli.Test/TrustedSigningCommandTests.cs
new file mode 100644
index 00000000..49e4b4ec
--- /dev/null
+++ b/test/Sign.Cli.Test/TrustedSigningCommandTests.cs
@@ -0,0 +1,162 @@
+// 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.
+
+using System.CommandLine;
+using System.CommandLine.Builder;
+using System.CommandLine.Parsing;
+using Moq;
+using Sign.Core;
+
+namespace Sign.Cli.Test
+{
+ public class TrustedSigningCommandTests
+ {
+ private readonly TrustedSigningCommand _command = new(new CodeCommand(), Mock.Of());
+
+ [Fact]
+ public void Constructor_WhenCodeCommandIsNull_Throws()
+ {
+ ArgumentNullException exception = Assert.Throws(
+ () => new TrustedSigningCommand(codeCommand: null!, Mock.Of()));
+
+ Assert.Equal("codeCommand", exception.ParamName);
+ }
+
+ [Fact]
+ public void Constructor_WhenServiceProviderFactoryIsNull_Throws()
+ {
+ ArgumentNullException exception = Assert.Throws(
+ () => new TrustedSigningCommand(new CodeCommand(), serviceProviderFactory: null!));
+
+ Assert.Equal("serviceProviderFactory", exception.ParamName);
+ }
+
+ [Fact]
+ public void EndpointOption_Always_HasArityOfExactlyOne()
+ {
+ Assert.Equal(ArgumentArity.ExactlyOne, _command.EndpointOption.Arity);
+ }
+
+ [Fact]
+ public void EndpointOption_Always_IsRequired()
+ {
+ Assert.True(_command.EndpointOption.IsRequired);
+ }
+
+ [Fact]
+ public void AccountOption_Always_HasArityOfExactlyOne()
+ {
+ Assert.Equal(ArgumentArity.ExactlyOne, _command.AccountOption.Arity);
+ }
+
+ [Fact]
+ public void AccountOption_Always_IsRequired()
+ {
+ Assert.True(_command.AccountOption.IsRequired);
+ }
+
+ [Fact]
+ public void CertificateProfileOption_Always_HasArityOfExactlyOne()
+ {
+ Assert.Equal(ArgumentArity.ExactlyOne, _command.CertificateProfileOption.Arity);
+ }
+
+ [Fact]
+ public void CertificateProfileOption_Always_IsRequired()
+ {
+ Assert.True(_command.CertificateProfileOption.IsRequired);
+ }
+
+ [Fact]
+ public void ManagedIdentityOption_Always_HasArityOfZeroOrOne()
+ {
+ Assert.Equal(ArgumentArity.ZeroOrOne, _command.ManagedIdentityOption.Arity);
+ }
+
+ [Fact]
+ public void ManagedIdentityOption_Always_IsNotRequired()
+ {
+ Assert.False(_command.ManagedIdentityOption.IsRequired);
+ }
+
+ [Fact]
+ public void TenantIdOption_Always_HasArityOfExactlyOne()
+ {
+ Assert.Equal(ArgumentArity.ExactlyOne, _command.TenantIdOption.Arity);
+ }
+
+ [Fact]
+ public void TenantIdOption_Always_IsNotRequired()
+ {
+ Assert.False(_command.TenantIdOption.IsRequired);
+ }
+
+ [Fact]
+ public void ClientIdOption_Always_HasArityOfExactlyOne()
+ {
+ Assert.Equal(ArgumentArity.ExactlyOne, _command.ClientIdOption.Arity);
+ }
+
+ [Fact]
+ public void ClientIdOption_Always_IsNotRequired()
+ {
+ Assert.False(_command.ClientIdOption.IsRequired);
+ }
+
+ [Fact]
+ public void ClientSecretOption_Always_HasArityOfExactlyOne()
+ {
+ Assert.Equal(ArgumentArity.ExactlyOne, _command.ClientSecretOption.Arity);
+ }
+
+ [Fact]
+ public void ClientSecretOption_Always_IsNotRequired()
+ {
+ Assert.False(_command.ClientSecretOption.IsRequired);
+ }
+
+ public class ParserTests
+ {
+ private readonly TrustedSigningCommand _command;
+ private readonly Parser _parser;
+
+ public ParserTests()
+ {
+ _command = new(new CodeCommand(), Mock.Of());
+ _parser = new CommandLineBuilder(_command).Build();
+ }
+
+ [Theory]
+ [InlineData("trusted-signing")]
+ [InlineData("trusted-signing a")]
+ [InlineData("trusted-signing -tse")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b -tst")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b -tst c")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b -tst c -tsi")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b -tst c -tsi d")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b -tst c -tsi d -tss")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b -tst c -tsi d -tss e")]
+ public void Command_WhenRequiredArgumentOrOptionsAreMissing_HasError(string command)
+ {
+ ParseResult result = _parser.Parse(command);
+
+ Assert.NotEmpty(result.Errors);
+ }
+
+ [Theory]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b -tsm c")]
+ [InlineData("trusted-signing -tse https://trustedsigning.test -tsa a -tsc b -tst c -tsi d -tss e f")]
+ public void Command_WhenRequiredArgumentsArePresent_HasNoError(string command)
+ {
+ ParseResult result = _parser.Parse(command);
+
+ Assert.Empty(result.Errors);
+ }
+ }
+ }
+}