Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions plugins/powershell-format/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "powershell-format",
"version": "0.7.7",
"description": "Auto-format and lint PowerShell on edit via PSScriptAnalyzer, only when a PSScriptAnalyzerSettings.psd1 governs the repo \u2014 using the consuming repo's own analyzer settings.",
"version": "0.7.8",
"description": "Auto-format and lint PowerShell on edit via PSScriptAnalyzer, only when a PSScriptAnalyzerSettings.psd1 governs the repo using the consuming repo's own analyzer settings.",
"author": {
"name": "Melodic Software",
"email": "info@melodicsoftware.com"
Expand Down
8 changes: 8 additions & 0 deletions plugins/powershell-format/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
All notable changes to the `powershell-format` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.7.8]

### Fixed

- **PSScriptAnalyzer trust scan treats `Invoke-Command -FilePath` and `Start-Job -FilePath`
with computed paths as unpinnable loaders (#1490).** Constant `-FilePath` arguments
remain pinned; non-constant ones are refused like other named loaders.

## [0.7.7]

### Changed
Expand Down
3 changes: 2 additions & 1 deletion plugins/powershell-format/hooks/powershell-format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,8 @@ PSSA_OUTPUT=$(PSSA_FILE="$PSSA_FILE_ARG" PSSA_SETTINGS="$PSSA_SETTINGS_ARG" \
# forms need no name match: InvocationOperator identifies them,
# and their element 0 IS the target, so it is checked too.
$loaders = @("Import-Module", "ipmo", "Add-Type", "New-Module",
"Invoke-Expression", "iex", "Import-PowerShellDataFile")
"Invoke-Expression", "iex", "Import-PowerShellDataFile",
"Invoke-Command", "Start-Job")
Comment thread
kyle-sexton marked this conversation as resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: adding Invoke-Command/Start-Job to $loaders will false-positive on ordinary remoting calls that load no file

The loop that consumes $loaders (L398-415) doesn't check which parameter a value belongs to — it skips only the CommandParameterAst tokens themselves (-ComputerName, -ArgumentList, -ScriptBlock, ...) and then treats every remaining non-constant command element as a load target requiring pinning, else it refuses with PSSA_TRUST UNPINNABLE (exit 6) at L415.

For the loaders added before this PR (Import-Module, Add-Type, New-Module, Invoke-Expression, Import-PowerShellDataFile), that's mostly harmless because those cmdlets effectively take one meaningful path/name argument. Invoke-Command and Start-Job break that assumption — they commonly take several variable arguments that have nothing to do with loading a file, e.g.:

Invoke-Command -ComputerName $server -ScriptBlock { ... } -ArgumentList $value
Start-Job -ScriptBlock { ... } -ArgumentList $value

Here $server/$value are VariableExpressionAst nodes, not StringConstantExpressionAst/ExpandableStringExpressionAst with fully-expandable content, so they fall through to the final else at L415 and the scan exits UNPINNABLE — permanently blocking the trust approval for a rule module that never loads a file this way, with "no approval route" (as Codex's review on this same line noted).

Since this hook's opt-in trust gate exists specifically so legitimate CustomRulePath modules can be approved (see README's Trust model section), a rule module using either cmdlet for ordinary remoting/job control — not file loading — would be unable to ever pass the gate. Given Invoke-Command/Start-Job are far more likely to appear in non-loading remoting/job-control usage than the previous loaders, suggest scoping the pinning check to the value bound to -FilePath specifically (as Codex suggested), rather than every non-parameter element, for these two entries.

Fix this →

$cmdAsts = $fileAst.FindAll({
param($n) $n -is [System.Management.Automation.Language.CommandAst]
}, $true)
Expand Down