|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.CommandLine;
using Microsoft.DotNet.Cli.Commands.Workload.Install;
using Microsoft.DotNet.Cli.Extensions;
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.EnvironmentAbstractions;
using NuGet.Common;
namespace Microsoft.DotNet.Cli.Commands.Workload;
/// <summary>
/// Base class for workload related commands.
/// </summary>
internal abstract class WorkloadCommandBase : CommandBase
{
/// <summary>
/// The package downloader to use for acquiring NuGet packages.
/// </summary>
protected INuGetPackageDownloader PackageDownloader
{
get;
}
/// <summary>
/// Provides basic output primitives for the command.
/// </summary>
protected IReporter Reporter
{
get;
}
/// <summary>
/// Configuration options used by NuGet when performing a restore.
/// </summary>
protected RestoreActionConfig RestoreActionConfiguration
{
get;
}
/// <summary>
/// Temporary directory used for downloading NuGet packages.
/// </summary>
protected DirectoryPath TempPackagesDirectory
{
get;
}
/// <summary>
/// The path of the temporary temporary directory to use.
/// </summary>
protected string TempDirectoryPath
{
get;
}
/// <summary>
/// The verbosity level to use when reporting output from the command.
/// </summary>
protected VerbosityOptions Verbosity
{
get;
}
/// <summary>
/// Gets whether signatures for workload packages and installers should be verified.
/// </summary>
protected bool VerifySignatures
{
get;
}
protected bool IsPackageDownloaderProvided { get; }
/// <summary>
/// Initializes a new <see cref="WorkloadCommandBase"/> instance.
/// </summary>
/// <param name="parseResult">The results of parsing the command line.</param>
/// <param name="verbosityOptions">The command line option used to define the verbosity level.</param>
/// <param name="reporter">The reporter to use for output.</param>
/// <param name="tempDirPath">The directory to use for volatile output. If no value is specified, the commandline
/// option is used if present, otherwise the default temp directory used.</param>
/// <param name="nugetPackageDownloader">The package downloader to use for acquiring NuGet packages.</param>
public WorkloadCommandBase(
ParseResult parseResult,
Option<VerbosityOptions>? verbosityOptions = null,
IReporter? reporter = null,
string? tempDirPath = null,
INuGetPackageDownloader? nugetPackageDownloader = null) : base(parseResult)
{
VerifySignatures = ShouldVerifySignatures(parseResult);
RestoreActionConfiguration = _parseResult.ToRestoreActionConfig();
Verbosity = verbosityOptions == null
? parseResult.GetValue(CommonOptions.VerbosityOption(VerbosityOptions.normal))
: parseResult.GetValue(verbosityOptions) ;
ILogger nugetLogger = Verbosity.IsDetailedOrDiagnostic() ? new NuGetConsoleLogger() : new NullLogger();
Reporter = reporter ?? Utils.Reporter.Output;
TempDirectoryPath = !string.IsNullOrWhiteSpace(tempDirPath)
? tempDirPath
: !string.IsNullOrWhiteSpace(parseResult.GetValue(WorkloadInstallCommandParser.TempDirOption))
? parseResult.GetValue(WorkloadInstallCommandParser.TempDirOption)!
: PathUtilities.CreateTempSubdirectory();
TempPackagesDirectory = new DirectoryPath(Path.Combine(TempDirectoryPath, "dotnet-sdk-advertising-temp"));
if (nugetPackageDownloader is not null)
{
IsPackageDownloaderProvided = true;
PackageDownloader = nugetPackageDownloader;
}
else
{
IsPackageDownloaderProvided = false;
PackageDownloader = new NuGetPackageDownloader.NuGetPackageDownloader(
TempPackagesDirectory,
filePermissionSetter: null,
new FirstPartyNuGetPackageSigningVerifier(),
nugetLogger,
Reporter,
restoreActionConfig: RestoreActionConfiguration,
verifySignatures: VerifySignatures,
shouldUsePackageSourceMapping: true);
}
}
/// <summary>
/// Determines whether workload packs and installer signatures should be verified based on whether
/// dotnet is signed, the skip option was specified, and whether a global policy enforcing verification
/// was set.
/// </summary>
/// <param name="parseResult">The results of parsing the command line.</param>
/// <returns><see langword="true"/> if signatures of packages and installers should be verified.</returns>
/// <exception cref="GracefulException" />
private static bool ShouldVerifySignatures(ParseResult parseResult) =>
ShouldVerifySignatures(parseResult.GetValue(WorkloadInstallCommandParser.SkipSignCheckOption));
public static bool ShouldVerifySignatures(bool skipSignCheck = false)
{
if (!SignCheck.IsDotNetSigned())
{
// Can't enforce anything if we already allowed an unsigned dotnet to be installed.
return false;
}
bool policyEnabled = SignCheck.IsWorkloadSignVerificationPolicySet();
if (skipSignCheck && policyEnabled)
{
// Can't override the global policy by using the skip option.
throw new GracefulException(CliCommandStrings.SkipSignCheckInvalidOption);
}
return !skipSignCheck;
}
}
|