Skip to content

Commit aeccd61

Browse files
Copilotbergmeister
andauthored
Reject invalid DSC resource-body pairings (#2286)
* Initial plan * Fix DSC resource body detection edge cases Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com> * Optimize DSC separator detection Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com>
1 parent 26f025c commit aeccd61

2 files changed

Lines changed: 50 additions & 0 deletions

File tree

‎Rules/AvoidAlias.cs‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ private ScriptBlockExpressionAst GetDscResourceBody(CommandAst cmdAst)
348348
&& bodyPipeline.PipelineElements.Count == 1
349349
&& bodyPipeline.PipelineElements[0] is CommandExpressionAst bodyExpression)
350350
{
351+
if (HasSemicolonSeparator(pipeline, bodyPipeline)
352+
|| bodyExpression.Redirections.Count != 0)
353+
{
354+
return null;
355+
}
356+
351357
return bodyExpression.Expression as ScriptBlockExpressionAst;
352358
}
353359

@@ -358,6 +364,26 @@ private ScriptBlockExpressionAst GetDscResourceBody(CommandAst cmdAst)
358364
return null;
359365
}
360366

367+
private bool HasSemicolonSeparator(Ast statement, Ast nextStatement)
368+
{
369+
int separatorStart = statement.Extent.EndOffset;
370+
int separatorLength = nextStatement.Extent.StartOffset - separatorStart;
371+
if (separatorLength <= 0)
372+
{
373+
return false;
374+
}
375+
376+
string script = statement.Extent.EndScriptPosition.GetFullScript();
377+
string separator = script.Substring(separatorStart, separatorLength);
378+
if (separator.IndexOf(';') < 0)
379+
{
380+
return false;
381+
}
382+
383+
Parser.ParseInput(separator, out Token[] tokens, out ParseError[] errors);
384+
return tokens.Any(token => token.Kind == TokenKind.Semi);
385+
}
386+
361387
/// <summary>
362388
/// For a command like "gci -path c:", returns the extent of "gci" in the command
363389
/// </summary>

‎Tests/Rules/AvoidUsingAlias.tests.ps1‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,30 @@ Configuration PackageTest {
232232
$_.SuggestedCorrections[0].Text | Should -Be 'Get-Verb'
233233
}
234234
}
235+
236+
It "does not pair following-line blocks with commands when the block has redirections or a statement terminator intervenes" {
237+
$target = @'
238+
{
239+
gci .
240+
{} > $null
241+
gci .; {}
242+
}
243+
'@
244+
$ast = [System.Management.Automation.Language.Parser]::ParseInput($target, [ref]$null, [ref]$null)
245+
$body = $ast.EndBlock.Statements[0].PipelineElements[0].Expression.Copy()
246+
$configuration = [System.Management.Automation.Language.ConfigurationDefinitionAst]::new(
247+
$ast.Extent, $body, 'Resource',
248+
[System.Management.Automation.Language.StringConstantExpressionAst]::new($ast.Extent, 'Test', 'BareWord'))
249+
$rule = [Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.AvoidAlias]::new()
250+
251+
$violations = @($rule.AnalyzeScript($configuration, $null))
252+
253+
$violations.Count | Should -Be 2
254+
$violations | ForEach-Object {
255+
$_.Extent.Text | Should -Be 'gci'
256+
$_.SuggestedCorrections[0].Text | Should -Be 'Get-ChildItem'
257+
}
258+
}
235259
}
236260

237261
Context "Settings file provides allowlist" {

0 commit comments

Comments
 (0)