diff --git a/README.md b/README.md index b4b8569298..2a3cce8068 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,7 @@ The following conceptual topics exist in the `PSRule` module: - [Execution.AliasReference](https://aka.ms/ps-rule/options#executionaliasreference) - [Execution.AliasReferenceWarning](https://aka.ms/ps-rule/options#executionaliasreferencewarning) - [Execution.DuplicateResourceId](https://aka.ms/ps-rule/options#executionduplicateresourceid) + - [Execution.HashAlgorithm](https://aka.ms/ps-rule/options#executionhashalgorithm) - [Execution.LanguageMode](https://aka.ms/ps-rule/options#executionlanguagemode) - [Execution.InconclusiveWarning](https://aka.ms/ps-rule/options#executioninconclusivewarning) - [Execution.InvariantCulture](https://aka.ms/ps-rule/options#executioninvariantculture) diff --git a/docs/CHANGELOG-v3.md b/docs/CHANGELOG-v3.md index 3491e53e81..bdf727fbbf 100644 --- a/docs/CHANGELOG-v3.md +++ b/docs/CHANGELOG-v3.md @@ -38,6 +38,13 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers What's changed since release v2.9.0: - General improvements: + - **Breaking change:** Switch to use SHA-512 for generating unbound objects by @BernieWhite. + [#1155](https://github.com/microsoft/PSRule/issues/1155) + - Objects that have no bound name will automatically be assigned a name based on the SHA-512 hash of the object. + - Previously a SHA-1 hash was used, however this is no longer considered secure. + - The name for unbound objects that are suppressed will change as a result. + - Additionally the hash can be changed by setting the `Execution.HashAlgorithm` option. + - See [upgrade notes][1] for details. - Expanded support for `FileHeader` assertion by @BernieWhite. [#1521](https://github.com/microsoft/PSRule/issues/1521) - Added support for `.bicepparam`, `.tsp`, `.tsx`, `.editorconfig`, `.ipynb`, and `.toml` files. diff --git a/docs/concepts/PSRule/en-US/about_PSRule_Options.md b/docs/concepts/PSRule/en-US/about_PSRule_Options.md index 8fc560c861..8773baf052 100644 --- a/docs/concepts/PSRule/en-US/about_PSRule_Options.md +++ b/docs/concepts/PSRule/en-US/about_PSRule_Options.md @@ -18,6 +18,7 @@ The following workspace options are available for use: - [Execution.AliasReference](#executionaliasreference) - [Execution.AliasReferenceWarning](#executionaliasreferencewarning) - [Execution.DuplicateResourceId](#executionduplicateresourceid) +- [Execution.HashAlgorithm](#executionhashalgorithm) - [Execution.LanguageMode](#executionlanguagemode) - [Execution.InconclusiveWarning](#executioninconclusivewarning) - [Execution.InvariantCulture](#executioninvariantculture) @@ -88,7 +89,8 @@ Options can be used with the following PSRule cmdlets: Each of these cmdlets support: -- Using the `-Option` parameter with an object created with the `New-PSRuleOption` cmdlet. See cmdlet help for syntax and examples. +- Using the `-Option` parameter with an object created with the `New-PSRuleOption` cmdlet. + See cmdlet help for syntax and examples. - Using the `-Option` parameter with a hashtable object. - Using the `-Option` parameter with a YAML file path. @@ -124,7 +126,8 @@ The `Set-PSRuleOption` cmdlet can be used to set options stored in YAML or the Y Set-PSRuleOption -OutputFormat Yaml; ``` -By default, PSRule will automatically look for a default YAML options file in the current working directory. Alternatively, you can specify a specific file path. +By default, PSRule will automatically look for a default YAML options file in the current working directory. +Alternatively, you can specify a specific file path. For example: @@ -426,21 +429,25 @@ _TargetName_ is used in output results to identify one object from another. Many objects could be passed down the pipeline at the same time, so using a _TargetName_ that is meaningful is important. _TargetName_ is also used for advanced features such as rule suppression. -The value that PSRule uses for _TargetName_ is configurable. PSRule uses the following logic to determine what _TargetName_ should be used: +The value that PSRule uses for _TargetName_ is configurable. +PSRule uses the following logic to determine what _TargetName_ should be used: - By default PSRule will: - Use `TargetName` or `Name` properties on the object. These property names are case insensitive. - If both `TargetName` and `Name` properties exist, `TargetName` will take precedence over `Name`. - - If neither `TargetName` or `Name` properties exist, a SHA1 hash of the object will be used as _TargetName_. + - If neither `TargetName` or `Name` properties exist, a hash of the object will be used as _TargetName_. + - The hash algorithm used can be set by the `Execution.HashAlgorithm` option. - If custom _TargetName_ binding properties are configured, the property names specified will override the defaults. - If **none** of the configured property names exist, PSRule will revert back to `TargetName` then `Name`. - If more then one property name is configured, the order they are specified in the configuration determines precedence. - i.e. The first configured property name will take precedence over the second property name. - - By default the property name will be matched ignoring case sensitivity. To use a case sensitive match, configure the [Binding.IgnoreCase](#bindingignorecase) option. + - By default the property name will be matched ignoring case sensitivity. + To use a case sensitive match, configure the [Binding.IgnoreCase](#bindingignorecase) option. - If a custom _TargetName_ binding function is specified, the function will be evaluated first before any other option. - If the function returns `$Null` then custom properties, `TargetName` and `Name` properties will be used. - The custom binding function is executed outside the PSRule engine, so PSRule keywords and variables will not be available. - - Custom binding functions are blocked in constrained language mode is used. See [language mode](#executionlanguagemode) for more information. + - Custom binding functions are blocked in constrained language mode is used. + See [language mode](#executionlanguagemode) for more information. Custom property names to use for binding can be specified using: @@ -515,11 +522,13 @@ PSRule uses the following logic to determine what _TargetType_ should be used: - If **none** of the configured property names exist, PSRule will revert back to the type presented by PowerShell. - If more then one property name is configured, the order they are specified in the configuration determines precedence. - i.e. The first configured property name will take precedence over the second property name. - - By default the property name will be matched ignoring case sensitivity. To use a case sensitive match, configure the [`Binding.IgnoreCase`](#bindingignorecase) option. + - By default the property name will be matched ignoring case sensitivity. + To use a case sensitive match, configure the [`Binding.IgnoreCase`](#bindingignorecase) option. - If a custom _TargetType_ binding function is specified, the function will be evaluated first before any other option. - If the function returns `$Null` then custom properties, or the type presented by PowerShell will be used in order instead. - The custom binding function is executed outside the PSRule engine, so PSRule keywords and variables will not be available. - - Custom binding functions are blocked in constrained language mode is used. See [language mode](#executionlanguagemode) for more information. + - Custom binding functions are blocked in constrained language mode is used. + See [language mode](#executionlanguagemode) for more information. Custom property names to use for binding can be specified using: @@ -897,6 +906,50 @@ variables: value: Warn ``` +### Execution.HashAlgorithm + +Specifies the hashing algorithm used by the PSRule runtime. +This hash algorithm is used when generating a resource identifier for an object that does not have a bound name. + +By default, the _SHA512_ algorithm is used. + +The following algorithms are available for use in PSRule: + +- SHA512 +- SHA384 +- SHA256 + +This option can be specified using: + +```powershell +# PowerShell: Using the Execution.HashAlgorithm hashtable key +$option = New-PSRuleOption -Option @{ 'Execution.HashAlgorithm' = 'SHA256' }; +``` + +```yaml +# YAML: Using the execution/hashAlgorithm property +execution: + hashAlgorithm: SHA256 +``` + +```bash +# Bash: Using environment variable +export PSRULE_EXECUTION_HASHALGORITHM=SHA256 +``` + +```yaml +# GitHub Actions: Using environment variable +env: + PSRULE_EXECUTION_HASHALGORITHM: SHA256 +``` + +```yaml +# Azure Pipelines: Using environment variable +variables: +- name: PSRULE_EXECUTION_HASHALGORITHM + value: SHA256 +``` + ### Execution.LanguageMode Unless PowerShell has been constrained, full language features of PowerShell are available to use within rule definitions. diff --git a/docs/upgrade-notes.md b/docs/upgrade-notes.md index f773404f45..8bfe545285 100644 --- a/docs/upgrade-notes.md +++ b/docs/upgrade-notes.md @@ -8,6 +8,27 @@ discussion: false This document contains notes to help upgrade from previous versions of PSRule. +## Upgrading to v3.0.0 + +### Unbound object names + +When an object is processed by PSRule, it is assigned a name. +This name is used to identify the object in the output and to suppress the object from future processing. + +Prior to _v3.0.0_, the name was generated using a SHA-1 hash of the object. +The SHA-1 algorithm is no longer considered secure and has been replaced with SHA-512. + +From _v3.0.0_, if the name of an object can not be determined, the SHA-512 hash of the object will be used. +Any objects that have previously been suppressed with a name based on a SHA-1 hash will no longer be suppressed. + +To resolve any issue caused by this change, you can: + +1. Configure binding by setting the [Binding.TargetName][1] option to set an alternative property to use as the name. _OR_ +2. Update any existing keys set with the [Suppression][2] option to use the new SHA-512 hash. + + [1]: https://aka.ms/ps-rule/options#bindingtargetname + [2]: https://aka.ms/ps-rule/options#suppression + ## Upgrading to v2.0.0 ### Resources naming restrictions diff --git a/schemas/PSRule-options.schema.json b/schemas/PSRule-options.schema.json index 0d0efa7d94..5ee9c25f23 100644 --- a/schemas/PSRule-options.schema.json +++ b/schemas/PSRule-options.schema.json @@ -328,6 +328,18 @@ ], "default": "Error" }, + "hashAlgorithm": { + "type": "string", + "title": "Hash Algorithm", + "description": "Configures the hashing algorithm used by the PSRule runtime. By default, SHA512 is used.", + "markdownDescription": "Configures the hashing algorithm used by the PSRule runtime.\n\nBy default, `SHA512` is used.\n\n[See help](https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#executionhashalgorithm)", + "enum": [ + "SHA512", + "SHA384", + "SHA256" + ], + "default": "SHA512" + }, "languageMode": { "type": "string", "title": "Language mode", diff --git a/src/PSRule.Tool/ClientHelper.cs b/src/PSRule.Tool/ClientHelper.cs index 3982177ce1..c07b5266ff 100644 --- a/src/PSRule.Tool/ClientHelper.cs +++ b/src/PSRule.Tool/ClientHelper.cs @@ -190,7 +190,7 @@ private static PSRuleOption GetOption(ClientHost host) { PSRuleOption.UseHostContext(host); var option = PSRuleOption.FromFileOrEmpty(); - option.Execution.InitialSessionState = Configuration.SessionState.Minimal; + option.Execution.InitialSessionState = Options.SessionState.Minimal; option.Input.Format = InputFormat.File; option.Output.Style ??= OutputStyle.Client; return option; diff --git a/src/PSRule/Configuration/ExecutionActionPreference.cs b/src/PSRule.Types/Options/ExecutionActionPreference.cs similarity index 96% rename from src/PSRule/Configuration/ExecutionActionPreference.cs rename to src/PSRule.Types/Options/ExecutionActionPreference.cs index 487b3bd677..13e57af5e2 100644 --- a/src/PSRule/Configuration/ExecutionActionPreference.cs +++ b/src/PSRule.Types/Options/ExecutionActionPreference.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PSRule.Configuration +namespace PSRule.Options { /// /// Determines the action to take for execution behaviors. diff --git a/src/PSRule/Configuration/ExecutionOption.cs b/src/PSRule.Types/Options/ExecutionOption.cs similarity index 95% rename from src/PSRule/Configuration/ExecutionOption.cs rename to src/PSRule.Types/Options/ExecutionOption.cs index d2467b500c..edad84eabb 100644 --- a/src/PSRule/Configuration/ExecutionOption.cs +++ b/src/PSRule.Types/Options/ExecutionOption.cs @@ -3,7 +3,7 @@ using System.ComponentModel; -namespace PSRule.Configuration +namespace PSRule.Options { /// /// Options that configure the execution sandbox. @@ -13,7 +13,7 @@ namespace PSRule.Configuration /// public sealed class ExecutionOption : IEquatable { - private const LanguageMode DEFAULT_LANGUAGEMODE = Configuration.LanguageMode.FullLanguage; + private const LanguageMode DEFAULT_LANGUAGEMODE = Options.LanguageMode.FullLanguage; private const ExecutionActionPreference DEFAULT_DUPLICATERESOURCEID = ExecutionActionPreference.Error; private const SessionState DEFAULT_INITIALSESSIONSTATE = SessionState.BuiltIn; private const ExecutionActionPreference DEFAULT_SUPPRESSIONGROUPEXPIRED = ExecutionActionPreference.Warn; @@ -23,10 +23,12 @@ public sealed class ExecutionOption : IEquatable private const ExecutionActionPreference DEFAULT_RULEINCONCLUSIVE = ExecutionActionPreference.Warn; private const ExecutionActionPreference DEFAULT_INVARIANTCULTURE = ExecutionActionPreference.Warn; private const ExecutionActionPreference DEFAULT_UNPROCESSEDOBJECT = ExecutionActionPreference.Warn; + private const HashAlgorithm DEFAULT_HASHALGORITHM = Options.HashAlgorithm.SHA512; internal static readonly ExecutionOption Default = new() { DuplicateResourceId = DEFAULT_DUPLICATERESOURCEID, + HashAlgorithm = DEFAULT_HASHALGORITHM, LanguageMode = DEFAULT_LANGUAGEMODE, InitialSessionState = DEFAULT_INITIALSESSIONSTATE, SuppressionGroupExpired = DEFAULT_SUPPRESSIONGROUPEXPIRED, @@ -46,6 +48,7 @@ public ExecutionOption() #pragma warning disable CS0618 // Type or member is obsolete AliasReferenceWarning = null; DuplicateResourceId = null; + HashAlgorithm = null; LanguageMode = null; InconclusiveWarning = null; InvariantCultureWarning = null; @@ -74,6 +77,7 @@ public ExecutionOption(ExecutionOption option) #pragma warning disable CS0618 // Type or member is obsolete AliasReferenceWarning = option.AliasReferenceWarning; DuplicateResourceId = option.DuplicateResourceId; + HashAlgorithm = option.HashAlgorithm; LanguageMode = option.LanguageMode; InconclusiveWarning = option.InconclusiveWarning; InvariantCultureWarning = option.InvariantCultureWarning; @@ -103,6 +107,7 @@ public bool Equals(ExecutionOption other) return other != null && AliasReferenceWarning == other.AliasReferenceWarning && DuplicateResourceId == other.DuplicateResourceId && + HashAlgorithm == other.HashAlgorithm && LanguageMode == other.LanguageMode && InconclusiveWarning == other.InconclusiveWarning && InvariantCultureWarning == other.InvariantCultureWarning && @@ -128,6 +133,7 @@ public override int GetHashCode() #pragma warning disable CS0618 // Type or member is obsolete hash = hash * 23 + (AliasReferenceWarning.HasValue ? AliasReferenceWarning.Value.GetHashCode() : 0); hash = hash * 23 + (DuplicateResourceId.HasValue ? DuplicateResourceId.Value.GetHashCode() : 0); + hash = hash * 23 + (HashAlgorithm.HasValue ? HashAlgorithm.Value.GetHashCode() : 0); hash = hash * 23 + (LanguageMode.HasValue ? LanguageMode.Value.GetHashCode() : 0); hash = hash * 23 + (InconclusiveWarning.HasValue ? InconclusiveWarning.Value.GetHashCode() : 0); hash = hash * 23 + (InvariantCultureWarning.HasValue ? InvariantCultureWarning.Value.GetHashCode() : 0); @@ -157,6 +163,7 @@ internal static ExecutionOption Combine(ExecutionOption o1, ExecutionOption o2) { AliasReferenceWarning = o1.AliasReferenceWarning ?? o2.AliasReferenceWarning, DuplicateResourceId = o1.DuplicateResourceId ?? o2.DuplicateResourceId, + HashAlgorithm = o1.HashAlgorithm ?? o2.HashAlgorithm, LanguageMode = o1.LanguageMode ?? o2.LanguageMode, InconclusiveWarning = o1.InconclusiveWarning ?? o2.InconclusiveWarning, NotProcessedWarning = o1.NotProcessedWarning ?? o2.NotProcessedWarning, @@ -192,6 +199,12 @@ internal static ExecutionOption Combine(ExecutionOption o1, ExecutionOption o2) [DefaultValue(null)] public ExecutionActionPreference? DuplicateResourceId { get; set; } + /// + /// Configures the hashing algorithm used by the PSRule runtime. + /// + [DefaultValue(null)] + public HashAlgorithm? HashAlgorithm { get; set; } + /// /// The langauge mode to execute PowerShell code with. /// @@ -330,6 +343,9 @@ internal static ExecutionOption Combine(ExecutionOption o1, ExecutionOption o2) /// internal void Load() { + if (Environment.TryEnum("PSRULE_EXECUTION_HASHALGORITHM", out HashAlgorithm hashAlgorithm)) + HashAlgorithm = hashAlgorithm; + #pragma warning disable CS0618 // Type or member is obsolete if (Environment.TryBool("PSRULE_EXECUTION_ALIASREFERENCEWARNING", out var bvalue)) AliasReferenceWarning = bvalue; @@ -383,6 +399,9 @@ internal void Load() /// internal void Load(Dictionary index) { + if (index.TryPopEnum("Execution.HashAlgorithm", out HashAlgorithm hashAlgorithm)) + HashAlgorithm = hashAlgorithm; + #pragma warning disable CS0618 // Type or member is obsolete if (index.TryPopBool("Execution.AliasReferenceWarning", out var bvalue)) AliasReferenceWarning = bvalue; diff --git a/src/PSRule.Types/Options/HashAlgorithm.cs b/src/PSRule.Types/Options/HashAlgorithm.cs new file mode 100644 index 0000000000..9891677f97 --- /dev/null +++ b/src/PSRule.Types/Options/HashAlgorithm.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace PSRule.Options +{ + /// + /// Configures the hashing algorithm used by the PSRule runtime. + /// + [JsonConverter(typeof(StringEnumConverter))] + public enum HashAlgorithm + { + /// + /// Use SHA256. + /// + SHA256, + + /// + /// Use SHA384. + /// + SHA384, + + /// + /// Use SHA512. + /// + SHA512 + } +} diff --git a/src/PSRule/Configuration/LanguageMode.cs b/src/PSRule.Types/Options/LanguageMode.cs similarity index 96% rename from src/PSRule/Configuration/LanguageMode.cs rename to src/PSRule.Types/Options/LanguageMode.cs index 53a4653ec0..d03a30bdb8 100644 --- a/src/PSRule/Configuration/LanguageMode.cs +++ b/src/PSRule.Types/Options/LanguageMode.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PSRule.Configuration +namespace PSRule.Options { /// /// Configures the language mode PowerShell code executes as within PSRule runtime. diff --git a/src/PSRule/Configuration/SessionState.cs b/src/PSRule.Types/Options/SessionState.cs similarity index 96% rename from src/PSRule/Configuration/SessionState.cs rename to src/PSRule.Types/Options/SessionState.cs index e330b1afd8..e1c31bfd93 100644 --- a/src/PSRule/Configuration/SessionState.cs +++ b/src/PSRule.Types/Options/SessionState.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PSRule.Configuration +namespace PSRule.Options { /// /// Configures how the initial PowerShell sandbox for executing rules is created. diff --git a/src/PSRule/Common/RunspaceContextDiagnosticExtensions.cs b/src/PSRule/Common/RunspaceContextDiagnosticExtensions.cs index 7c402e1ce7..cbefaa8eaa 100644 --- a/src/PSRule/Common/RunspaceContextDiagnosticExtensions.cs +++ b/src/PSRule/Common/RunspaceContextDiagnosticExtensions.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using PSRule.Configuration; +using PSRule.Options; using PSRule.Definitions; using PSRule.Pipeline; using PSRule.Resources; diff --git a/src/PSRule/Configuration/PSRuleOption.cs b/src/PSRule/Configuration/PSRuleOption.cs index db58cb5c29..a422e0c154 100644 --- a/src/PSRule/Configuration/PSRuleOption.cs +++ b/src/PSRule/Configuration/PSRuleOption.cs @@ -36,7 +36,7 @@ public sealed class PSRuleOption : IEquatable, IBaselineV1Spec Baseline = Options.BaselineOption.Default, Binding = BindingOption.Default, Convention = ConventionOption.Default, - Execution = ExecutionOption.Default, + Execution = Options.ExecutionOption.Default, Include = IncludeOption.Default, Input = InputOption.Default, Logging = LoggingOption.Default, @@ -54,7 +54,7 @@ public PSRuleOption() Binding = new BindingOption(); Configuration = new ConfigurationOption(); Convention = new ConventionOption(); - Execution = new ExecutionOption(); + Execution = new Options.ExecutionOption(); Include = new IncludeOption(); Input = new InputOption(); Logging = new LoggingOption(); @@ -75,7 +75,7 @@ private PSRuleOption(string sourcePath, PSRuleOption option) Binding = new BindingOption(option?.Binding); Configuration = new ConfigurationOption(option?.Configuration); Convention = new ConventionOption(option?.Convention); - Execution = new ExecutionOption(option?.Execution); + Execution = new Options.ExecutionOption(option?.Execution); Include = new IncludeOption(option?.Include); Input = new InputOption(option?.Input); Logging = new LoggingOption(option?.Logging); @@ -110,7 +110,7 @@ private PSRuleOption(string sourcePath, PSRuleOption option) /// /// Options that configure the execution sandbox. /// - public ExecutionOption Execution { get; set; } + public Options.ExecutionOption Execution { get; set; } /// /// Options that affect source locations imported for execution. @@ -210,7 +210,7 @@ private static PSRuleOption Combine(PSRuleOption o1, PSRuleOption o2) result.Binding = BindingOption.Combine(result.Binding, o2?.Binding); result.Configuration = ConfigurationOption.Combine(result.Configuration, o2?.Configuration); result.Convention = ConventionOption.Combine(result.Convention, o2?.Convention); - result.Execution = ExecutionOption.Combine(result.Execution, o2?.Execution); + result.Execution = Options.ExecutionOption.Combine(result.Execution, o2?.Execution); result.Include = IncludeOption.Combine(result.Include, o2?.Include); result.Input = InputOption.Combine(result.Input, o2?.Input); result.Logging = LoggingOption.Combine(result.Logging, o2?.Logging); diff --git a/src/PSRule/Host/Host.cs b/src/PSRule/Host/Host.cs index 622a3da961..d2143fb193 100644 --- a/src/PSRule/Host/Host.cs +++ b/src/PSRule/Host/Host.cs @@ -147,9 +147,9 @@ internal static class HostState /// /// Create a default session state. /// - public static InitialSessionState CreateSessionState(Configuration.SessionState initialSessionState) + public static InitialSessionState CreateSessionState(Options.SessionState initialSessionState) { - var state = initialSessionState == Configuration.SessionState.Minimal ? + var state = initialSessionState == Options.SessionState.Minimal ? InitialSessionState.CreateDefault2() : InitialSessionState.CreateDefault(); // Add in language elements diff --git a/src/PSRule/PSRule.psm1 b/src/PSRule/PSRule.psm1 index cb70c293a5..de0e6e74fa 100644 --- a/src/PSRule/PSRule.psm1 +++ b/src/PSRule/PSRule.psm1 @@ -125,7 +125,7 @@ function Invoke-PSRule { # If DeviceGuard is enabled, force a contrained execution environment if ($isDeviceGuard) { - $Option.Execution.LanguageMode = [PSRule.Configuration.LanguageMode]::ConstrainedLanguage; + $Option.Execution.LanguageMode = [PSRule.Options.LanguageMode]::ConstrainedLanguage; } if ($PSBoundParameters.ContainsKey('Format')) { $Option.Input.Format = $Format; @@ -283,7 +283,7 @@ function Test-PSRuleTarget { # If DeviceGuard is enabled, force a contrained execution environment if ($isDeviceGuard) { - $Option.Execution.LanguageMode = [PSRule.Configuration.LanguageMode]::ConstrainedLanguage; + $Option.Execution.LanguageMode = [PSRule.Options.LanguageMode]::ConstrainedLanguage; } if ($PSBoundParameters.ContainsKey('Format')) { $Option.Input.Format = $Format; @@ -389,7 +389,7 @@ function Get-PSRuleTarget { # If DeviceGuard is enabled, force a contrained execution environment if ($isDeviceGuard) { - $Option.Execution.LanguageMode = [PSRule.Configuration.LanguageMode]::ConstrainedLanguage; + $Option.Execution.LanguageMode = [PSRule.Options.LanguageMode]::ConstrainedLanguage; } if ($PSBoundParameters.ContainsKey('Format')) { $Option.Input.Format = $Format; @@ -556,7 +556,7 @@ function Assert-PSRule { # If DeviceGuard is enabled, force a contrained execution environment if ($isDeviceGuard) { - $Option.Execution.LanguageMode = [PSRule.Configuration.LanguageMode]::ConstrainedLanguage; + $Option.Execution.LanguageMode = [PSRule.Options.LanguageMode]::ConstrainedLanguage; } if ($PSBoundParameters.ContainsKey('Format')) { $Option.Input.Format = $Format; @@ -718,7 +718,7 @@ function Get-PSRule { # If DeviceGuard is enabled, force a contrained execution environment if ($isDeviceGuard) { - $Option.Execution.LanguageMode = [PSRule.Configuration.LanguageMode]::ConstrainedLanguage; + $Option.Execution.LanguageMode = [PSRule.Options.LanguageMode]::ConstrainedLanguage; } if ($PSBoundParameters.ContainsKey('OutputFormat')) { $Option.Output.Format = $OutputFormat; @@ -1051,7 +1051,7 @@ function Get-PSRuleHelp { # If DeviceGuard is enabled, force a contrained execution environment if ($isDeviceGuard) { - $Option.Execution.LanguageMode = [PSRule.Configuration.LanguageMode]::ConstrainedLanguage; + $Option.Execution.LanguageMode = [PSRule.Options.LanguageMode]::ConstrainedLanguage; } if ($PSBoundParameters.ContainsKey('Culture')) { $Option.Output.Culture = $Culture; @@ -1171,7 +1171,7 @@ function New-PSRuleOption { # Sets the Execution.DuplicateResourceId option [Parameter(Mandatory = $False)] [Alias('ExecutionDuplicateResourceId')] - [PSRule.Configuration.ExecutionActionPreference]$DuplicateResourceId = [PSRule.Configuration.ExecutionActionPreference]::Error, + [PSRule.Options.ExecutionActionPreference]$DuplicateResourceId = [PSRule.Options.ExecutionActionPreference]::Error, # Sets the Execution.InconclusiveWarning option [Parameter(Mandatory = $False)] @@ -1186,7 +1186,7 @@ function New-PSRuleOption { # Sets the Execution.InitialSessionState option [Parameter(Mandatory = $False)] [Alias('ExecutionInitialSessionState')] - [PSRule.Configuration.SessionState]$InitialSessionState = [PSRule.Configuration.SessionState]::BuiltIn, + [PSRule.Options.SessionState]$InitialSessionState = [PSRule.Options.SessionState]::BuiltIn, # Sets the Execution.NotProcessedWarning option [Parameter(Mandatory = $False)] @@ -1202,31 +1202,31 @@ function New-PSRuleOption { # Sets the Execution.SuppressionGroupExpired option [Parameter(Mandatory = $False)] [Alias('ExecutionSuppressionGroupExpired')] - [PSRule.Configuration.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.RuleExcluded option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Configuration.ExecutionActionPreference]::Ignore, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Options.ExecutionActionPreference]::Ignore, # Sets the Execution.RuleSuppressed option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.AliasReference option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionAliasReference = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionAliasReference = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.RuleInconclusive option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleInconclusive = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleInconclusive = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.InvariantCulture option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionInvariantCulture = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionInvariantCulture = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.UnprocessedObject option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionUnprocessedObject = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionUnprocessedObject = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Include.Module option [Parameter(Mandatory = $False)] @@ -1501,7 +1501,7 @@ function Set-PSRuleOption { # Sets the Execution.DuplicateResourceId option [Parameter(Mandatory = $False)] [Alias('ExecutionDuplicateResourceId')] - [PSRule.Configuration.ExecutionActionPreference]$DuplicateResourceId = [PSRule.Configuration.ExecutionActionPreference]::Error, + [PSRule.Options.ExecutionActionPreference]$DuplicateResourceId = [PSRule.Options.ExecutionActionPreference]::Error, # Sets the Execution.InconclusiveWarning option [Parameter(Mandatory = $False)] @@ -1516,7 +1516,7 @@ function Set-PSRuleOption { # Sets the Execution.InitialSessionState option [Parameter(Mandatory = $False)] [Alias('ExecutionInitialSessionState')] - [PSRule.Configuration.SessionState]$InitialSessionState = [PSRule.Configuration.SessionState]::BuiltIn, + [PSRule.Options.SessionState]$InitialSessionState = [PSRule.Options.SessionState]::BuiltIn, # Sets the Execution.NotProcessedWarning option [Parameter(Mandatory = $False)] @@ -1532,31 +1532,31 @@ function Set-PSRuleOption { # Sets the Execution.SuppressionGroupExpired option [Parameter(Mandatory = $False)] [Alias('ExecutionSuppressionGroupExpired')] - [PSRule.Configuration.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.RuleExcluded option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Configuration.ExecutionActionPreference]::Ignore, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Options.ExecutionActionPreference]::Ignore, # Sets the Execution.RuleSuppressed option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.AliasReference option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionAliasReference = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionAliasReference = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.RuleInconclusive option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleInconclusive = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleInconclusive = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.InvariantCulture option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionInvariantCulture = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionInvariantCulture = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.UnprocessedObject option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionUnprocessedObject = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionUnprocessedObject = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Include.Module option [Parameter(Mandatory = $False)] @@ -2278,7 +2278,7 @@ function SetOptions { # Sets the Execution.DuplicateResourceId option [Parameter(Mandatory = $False)] [Alias('ExecutionDuplicateResourceId')] - [PSRule.Configuration.ExecutionActionPreference]$DuplicateResourceId = [PSRule.Configuration.ExecutionActionPreference]::Error, + [PSRule.Options.ExecutionActionPreference]$DuplicateResourceId = [PSRule.Options.ExecutionActionPreference]::Error, # Sets the Execution.InconclusiveWarning option [Parameter(Mandatory = $False)] @@ -2293,7 +2293,7 @@ function SetOptions { # Sets the Execution.InitialSessionState option [Parameter(Mandatory = $False)] [Alias('ExecutionInitialSessionState')] - [PSRule.Configuration.SessionState]$InitialSessionState = [PSRule.Configuration.SessionState]::BuiltIn, + [PSRule.Options.SessionState]$InitialSessionState = [PSRule.Options.SessionState]::BuiltIn, # Sets the Execution.NotProcessedWarning option [Parameter(Mandatory = $False)] @@ -2308,31 +2308,31 @@ function SetOptions { # Sets the Execution.SuppressionGroupExpired option [Parameter(Mandatory = $False)] [Alias('ExecutionSuppressionGroupExpired')] - [PSRule.Configuration.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.RuleExcluded option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Configuration.ExecutionActionPreference]::Ignore, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Options.ExecutionActionPreference]::Ignore, # Sets the Execution.RuleSuppressed option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.AliasReference option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionAliasReference = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionAliasReference = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.RuleInconclusive option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleInconclusive = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionRuleInconclusive = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.InvariantCulture option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionInvariantCulture = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionInvariantCulture = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Execution.UnprocessedObject option [Parameter(Mandatory = $False)] - [PSRule.Configuration.ExecutionActionPreference]$ExecutionUnprocessedObject = [PSRule.Configuration.ExecutionActionPreference]::Warn, + [PSRule.Options.ExecutionActionPreference]$ExecutionUnprocessedObject = [PSRule.Options.ExecutionActionPreference]::Warn, # Sets the Include.Module option [Parameter(Mandatory = $False)] diff --git a/src/PSRule/Pipeline/GetRuleHelpPipeline.cs b/src/PSRule/Pipeline/GetRuleHelpPipeline.cs index 3f5c5b5abc..15f555a6e7 100644 --- a/src/PSRule/Pipeline/GetRuleHelpPipeline.cs +++ b/src/PSRule/Pipeline/GetRuleHelpPipeline.cs @@ -5,6 +5,7 @@ using System.Management.Automation; using PSRule.Configuration; using PSRule.Host; +using PSRule.Options; using PSRule.Resources; using PSRule.Rules; diff --git a/src/PSRule/Pipeline/PipelineBuilder.cs b/src/PSRule/Pipeline/PipelineBuilder.cs index 1e34f97a78..8fdd2552ad 100644 --- a/src/PSRule/Pipeline/PipelineBuilder.cs +++ b/src/PSRule/Pipeline/PipelineBuilder.cs @@ -8,6 +8,7 @@ using PSRule.Data; using PSRule.Definitions; using PSRule.Definitions.Baselines; +using PSRule.Options; using PSRule.Pipeline.Output; using PSRule.Resources; @@ -179,7 +180,7 @@ public interface IPipelineBuilder /// Configure the pipeline to use a specific baseline. /// /// A baseline option or the name of a baseline. - void Baseline(BaselineOption baseline); + void Baseline(Configuration.BaselineOption baseline); /// /// Build the pipeline. @@ -284,7 +285,7 @@ internal abstract class PipelineBuilderBase : IPipelineBuilder private string[] _Include; private Hashtable _Tag; - private BaselineOption _Baseline; + private Configuration.BaselineOption _Baseline; private string[] _Convention; private PathFilter _InputFilter; private PipelineWriter _Writer; @@ -365,13 +366,13 @@ public virtual IPipelineBuilder Configure(PSRuleOption option) /// Use a baseline, either by name or by path. /// [Obsolete()] - public void UseBaseline(BaselineOption baseline) + public void UseBaseline(Configuration.BaselineOption baseline) { Baseline(baseline); } /// - public void Baseline(BaselineOption baseline) + public void Baseline(Configuration.BaselineOption baseline) { if (baseline == null) return; @@ -437,7 +438,7 @@ private static bool TryModuleVersion(string moduleVersion, string requiredVersio protected PipelineContext PrepareContext(BindTargetMethod bindTargetName, BindTargetMethod bindTargetType, BindTargetMethod bindField) { var unresolved = new List(); - if (_Baseline is BaselineOption.BaselineRef baselineRef) + if (_Baseline is Configuration.BaselineOption.BaselineRef baselineRef) unresolved.Add(new BaselineRef(ResolveBaselineGroup(baselineRef.Name), OptionContext.ScopeType.Explicit)); return PipelineContext.New( diff --git a/src/PSRule/Pipeline/PipelineContext.cs b/src/PSRule/Pipeline/PipelineContext.cs index da6a895b88..73badf6bdc 100644 --- a/src/PSRule/Pipeline/PipelineContext.cs +++ b/src/PSRule/Pipeline/PipelineContext.cs @@ -14,6 +14,7 @@ using PSRule.Definitions.Selectors; using PSRule.Definitions.SuppressionGroups; using PSRule.Host; +using PSRule.Options; using PSRule.Resources; using PSRule.Runtime; using PSRule.Runtime.ObjectPath; @@ -38,7 +39,6 @@ internal sealed class PipelineContext : IDisposable, IBindingContext // Objects kept for caching and disposal private Runspace _Runspace; - private SHA1Managed _Hash; // Track whether Dispose has been called. private bool _Disposed; @@ -60,14 +60,7 @@ internal sealed class PipelineContext : IDisposable, IBindingContext internal readonly Stopwatch RunTime; - public HashAlgorithm ObjectHashAlgorithm - { - get - { - _Hash ??= new SHA1Managed(); - return _Hash; - } - } + public System.Security.Cryptography.HashAlgorithm ObjectHashAlgorithm { get; } private PipelineContext(PSRuleOption option, IHostContext hostContext, PipelineReader reader, BindTargetMethod bindTargetName, BindTargetMethod bindTargetType, BindTargetMethod bindField, OptionContext baseline, IList unresolved) { @@ -87,6 +80,8 @@ private PipelineContext(PSRuleOption option, IHostContext hostContext, PipelineR Baseline = baseline; _Unresolved = unresolved ?? new List(); _TrackedIssues = new List(); + + ObjectHashAlgorithm = GetHashAlgorithm(option.Execution.HashAlgorithm.GetValueOrDefault(ExecutionOption.Default.HashAlgorithm.Value)); RunId = Environment.GetRunId() ?? ObjectHashAlgorithm.GetDigest(Guid.NewGuid().ToByteArray()); RunTime = Stopwatch.StartNew(); } @@ -280,6 +275,14 @@ private void ReportIssue(RunspaceContext runspaceContext) // runspaceContext.WarnMissingApiVersion(_TrackedIssues[i].Kind, _TrackedIssues[i].Id); } + private static System.Security.Cryptography.HashAlgorithm GetHashAlgorithm(Options.HashAlgorithm hashAlgorithm) + { + if (hashAlgorithm == Options.HashAlgorithm.SHA256) + return SHA256.Create(); + + return hashAlgorithm == Options.HashAlgorithm.SHA384 ? SHA384.Create() : SHA512.Create(); + } + #region IBindingContext public bool GetPathExpression(string path, out PathExpression expression) @@ -307,7 +310,7 @@ private void Dispose(bool disposing) { if (disposing) { - _Hash?.Dispose(); + ObjectHashAlgorithm?.Dispose(); _Runspace?.Dispose(); _PathExpressionCache.Clear(); LocalizedDataCache.Clear(); diff --git a/src/PSRule/Pipeline/PipelineHookActions.cs b/src/PSRule/Pipeline/PipelineHookActions.cs index 2d6afdddb1..1eb4c34a2d 100644 --- a/src/PSRule/Pipeline/PipelineHookActions.cs +++ b/src/PSRule/Pipeline/PipelineHookActions.cs @@ -143,7 +143,7 @@ private static string NestedTargetPropertyBinding(string[] propertyNames, bool c } /// - /// Calculate a SHA1 hash for an object to use as TargetName. + /// Calculate a hash for an object to use as TargetName. /// /// A PSObject to hash. /// The TargetName of the object. @@ -159,7 +159,8 @@ private static string GetUnboundObjectTargetName(object targetObject) settings.Converters.Insert(0, new PSObjectJsonConverter()); var json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(targetObject, settings)); - return PipelineContext.CurrentThread.ObjectHashAlgorithm.GetDigest(json); + var name = PipelineContext.CurrentThread.ObjectHashAlgorithm.GetDigest(json); + return name.Substring(0, name.Length > 50 ? 50 : name.Length); } /// diff --git a/src/PSRule/Runtime/RunspaceContext.cs b/src/PSRule/Runtime/RunspaceContext.cs index a43dbed8e1..508eb42129 100644 --- a/src/PSRule/Runtime/RunspaceContext.cs +++ b/src/PSRule/Runtime/RunspaceContext.cs @@ -6,6 +6,7 @@ using System.Management.Automation.Language; using PSRule.Configuration; using PSRule.Definitions; +using PSRule.Options; using PSRule.Pipeline; using PSRule.Resources; using PSRule.Rules; diff --git a/tests/PSRule.Tests/PSRule.Common.Tests.ps1 b/tests/PSRule.Tests/PSRule.Common.Tests.ps1 index 70303cb089..cec8c482e6 100644 --- a/tests/PSRule.Tests/PSRule.Common.Tests.ps1 +++ b/tests/PSRule.Tests/PSRule.Common.Tests.ps1 @@ -2775,13 +2775,13 @@ Describe 'Binding' -Tag Common, Binding { $result | Should -Not -BeNullOrEmpty; $result.Length | Should -Be 7; $result[0..6].IsSuccess() | Should -BeIn $True; - $result[0].TargetName | Should -BeIn 'f209c623345144be61087d91f30c17b01c6e86d2'; - $result[1].TargetName | Should -BeIn '28e156a7121bc57b0461029208daf0b48d1c4fd0'; - $result[2].TargetName | Should -BeIn '3b8eeb35831ea8f7b5de4e0cf04f32b9a1233a0d'; - $result[3].TargetName | Should -BeIn '7b3ce68b6c2f7d67dae4210eeb83be69f978e2a8'; - $result[4].TargetName | Should -BeIn '205c97d9248d2cd12db1c55ba421eb8df84b22a7'; - $result[5].TargetName | Should -BeIn '356a192b7913b04c54574d18c28d46e6395428ab'; - $result[6].TargetName | Should -BeIn 'da4b9237bacccdf19c0760cab7aec4a8359010b0'; + $result[0].TargetName | Should -BeIn 'f3d2f8ce966af96a8d320e8f5c088604324885a0d02f44b174'; + $result[1].TargetName | Should -BeIn '839b3457fca709821c89e23263a070fdca7cb8c4a86b5862f9'; + $result[2].TargetName | Should -BeIn '1c23e67aab1f653e2ead0b0e71153d02eb249f1c8382821598'; + $result[3].TargetName | Should -BeIn '72dd48c5f3cef36c66f5633955719b5cdb5f679539ec39b087'; + $result[4].TargetName | Should -BeIn '35f8cb2a8d4c26a7d53839be143c5d5b82e1543ce27adb94d4'; + $result[5].TargetName | Should -BeIn '4dff4ea340f0a823f15d3f4f01ab62eae0e5da579ccb851f8d'; + $result[6].TargetName | Should -BeIn '40b244112641dd78dd4f93b6c9190dd46e0099194d5a44257b'; } It 'Binds to custom name' { diff --git a/tests/PSRule.Tests/PSRule.Options.Tests.ps1 b/tests/PSRule.Tests/PSRule.Options.Tests.ps1 index 0ba4396a01..25e184d4ee 100644 --- a/tests/PSRule.Tests/PSRule.Options.Tests.ps1 +++ b/tests/PSRule.Tests/PSRule.Options.Tests.ps1 @@ -635,6 +635,34 @@ Describe 'New-PSRuleOption' -Tag 'Option','New-PSRuleOption' { } } + Context 'Read Execution.HashAlgorithm' { + It 'from default' { + $option = New-PSRuleOption -Default; + $option.Execution.HashAlgorithm | Should -Be 'SHA512'; + } + + It 'from Hashtable' { + $option = New-PSRuleOption -Option @{ 'Execution.HashAlgorithm' = 'SHA256' }; + $option.Execution.HashAlgorithm | Should -Be 'SHA256'; + } + + It 'from YAML' { + $option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests.yml'); + $option.Execution.HashAlgorithm | Should -Be 'SHA256'; + } + + It 'from Environment' { + try { + $Env:PSRULE_EXECUTION_HASHALGORITHM = 'SHA256'; + $option = New-PSRuleOption; + $option.Execution.HashAlgorithm | Should -Be 'SHA256'; + } + finally { + Remove-Item 'Env:PSRULE_EXECUTION_HASHALGORITHM' -Force; + } + } + } + Context 'Read Execution.LanguageMode' { It 'from default' { $option = New-PSRuleOption -Default; diff --git a/tests/PSRule.Tests/PSRule.Tests.yml b/tests/PSRule.Tests/PSRule.Tests.yml index 543ad61d1a..6c3d8761e0 100644 --- a/tests/PSRule.Tests/PSRule.Tests.yml +++ b/tests/PSRule.Tests/PSRule.Tests.yml @@ -56,6 +56,7 @@ execution: aliasReference: Ignore aliasReferenceWarning: false duplicateResourceId: Warn + hashAlgorithm: SHA256 languageMode: ConstrainedLanguage inconclusiveWarning: false invariantCulture: Ignore diff --git a/tests/PSRule.Tests/PipelineTests.cs b/tests/PSRule.Tests/PipelineTests.cs index e6ec105cbd..84fc350536 100644 --- a/tests/PSRule.Tests/PipelineTests.cs +++ b/tests/PSRule.Tests/PipelineTests.cs @@ -9,6 +9,7 @@ using System.Threading; using Newtonsoft.Json.Linq; using PSRule.Configuration; +using PSRule.Options; using PSRule.Pipeline; using PSRule.Resources; using PSRule.Rules; @@ -163,7 +164,7 @@ public void GetRuleWithBaseline() "Baseline.Rule.yaml", "FromFileBaseline.Rule.ps1" }), option, null); - builder.Baseline(BaselineOption.FromString("@test")); + builder.Baseline(Configuration.BaselineOption.FromString("@test")); var writer = new TestWriter(option); var pipeline = builder.Build(writer); diff --git a/tests/PSRule.Tests/TargetNameBindingTests.cs b/tests/PSRule.Tests/TargetNameBindingTests.cs index 575cf1a1f6..7ced67040b 100644 --- a/tests/PSRule.Tests/TargetNameBindingTests.cs +++ b/tests/PSRule.Tests/TargetNameBindingTests.cs @@ -4,6 +4,7 @@ using System.Management.Automation; using PSRule.Configuration; using PSRule.Data; +using PSRule.Options; using PSRule.Pipeline; namespace PSRule @@ -39,12 +40,17 @@ public void UnboundObjectTargetName() var pso1 = PSObject.AsPSObject(testObject1); var pso2 = PSObject.AsPSObject(testObject2); + // SHA512 PipelineContext.CurrentThread = PipelineContext.New(GetOption(), null, null, null, null, null, null, null); - var actual1 = PipelineHookActions.BindTargetName(null, false, false, pso1, out _); - var actual2 = PipelineHookActions.BindTargetName(null, false, false, pso2, out _); - Assert.Equal(expected: "f209c623345144be61087d91f30c17b01c6e86d2", actual: actual1); - Assert.Equal(expected: "f209c623345144be61087d91f30c17b01c6e86d2", actual: actual2); + Assert.Equal("f3d2f8ce966af96a8d320e8f5c088604324885a0d02f44b174", PipelineHookActions.BindTargetName(null, false, false, pso1, out _)); + Assert.Equal("f3d2f8ce966af96a8d320e8f5c088604324885a0d02f44b174", PipelineHookActions.BindTargetName(null, false, false, pso2, out _)); + + // SHA256 + PipelineContext.CurrentThread = PipelineContext.New(GetOption(HashAlgorithm.SHA256), null, null, null, null, null, null, null); + + Assert.Equal("67327c8cd8622d17cf1702a76cbbb685e9ef260ce39c9f6779", PipelineHookActions.BindTargetName(null, false, false, pso1, out _)); + Assert.Equal("67327c8cd8622d17cf1702a76cbbb685e9ef260ce39c9f6779", PipelineHookActions.BindTargetName(null, false, false, pso2, out _)); } [Fact] @@ -68,9 +74,13 @@ public void PreferTargetInfo() Assert.Null(path); } - private static PSRuleOption GetOption() + private static PSRuleOption GetOption(HashAlgorithm? hashAlgorithm = null) { - return new PSRuleOption(); + var option = new PSRuleOption(); + if (hashAlgorithm != null) + option.Execution.HashAlgorithm = hashAlgorithm; + + return option; } } }