Use case:
We are running GitLab Code Quality reports in our pipeline based on the PSScriptAnalyzer results by translating the PSScriptAnalyzer severity results to a Code Quality severity.
But it appears that engineers might simply take the easy way by suppressing rules rather than investigating time in improving the code (and going through the whole process of retesting etc.)
For this I created a PSAvoidRuleSuppression "information" rule so that any rule suppression might pass through but won't be unnoticed:
using namespace System.Management.Automation.Language
function Measure-AvoidSecureStringDisclosure {
[CmdletBinding()]
[OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord])]
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[ScriptBlockAst]
$ScriptBlockAst
)
process {
[ScriptBlock]$Predicate = {
param ([Ast]$Ast)
$Ast -is [AttributeAst] -and
$Ast.TypeName.FullName -eq 'System.Diagnostics.CodeAnalysis.SuppressMessageAttribute'
}
$Violations = $ScriptBlockAst.FindAll($Predicate, $False)
foreach ($Violation in $Violations) {
$Extent = $Violation.Extent
[Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{
Message = "Avoid rule suppression: $Extent"
Extent = $Extent
RuleName = 'PSAvoidRuleSuppression'
Severity = # In case the suppression is for the rule itself, we want to mark it as an error.
if ($Violation.PositionalArguments[0].Value -eq 'PSAvoidRuleSuppression') {
'Error'
} else {
'Information'
}
RuleSuppressionID = $null
}
}
}
}
Export-ModuleMember -Function Measure-*
This rule works well, but there is a hole in it: script authors might simply suppress the rule itself like:
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidRuleSuppression', '')]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
Param()
Write-Host 'Test'
One way around this, is to create a unique rule name, e.g.
RuleName = 'PSAvoidRuleSuppression ' + [Guid]::NewGuid().Guid`
But I rather prefer to higher the severity to error (in case of a "self-suppression") as shown in the above rule definition as that would result into a code quality blocker in our GitLab pipeline.
Unfortunately, it appears not to work that way as the rule is already suppressed before it could be evaluated with PowerShell.
Is there anyway to work around this?
gci -Filter *.ps1 -Recurse | where { Select-String $_ -Pattern SuppressMessageAttribute } | %{ Write-Error "AHA! do not suppress my rules here $_" -ErrorAction Continue }