Skip to content

disk-hygiene: the PowerShell belt does not flag >> append redirection #2675

Description

@kyle-sexton

Problem

The PowerShell belt does not flag >> (append) redirection. A command that appends to a file
runs with no prompt, while the same command using > prompts.

plugins/disk-hygiene/skills/clean/scripts/destructive_guard.py, on current main:

_POWERSHELL_OUTPUT_REDIRECT = re.compile(r"(?<![<>])>(?![=>&])")

The negative lookahead (?![=>&]) rejects a > followed by another >, so the first > of a
>> pair never matches. The second > is then rejected by the lookbehind (?<![<>]). Neither
character in the pair can match, so >> is invisible to the pattern.

Nothing else covers it. _POWERSHELL_MUTATION_WORDS catches the cmdlet spellings
(out-file, add-content, set-content) but not a bare shell append.

Reproduction

Get-ChildItem C:/tmp >> append.txt

No prompt. Compare:

Get-ChildItem C:/tmp > out.txt

Prompts, correctly.

Verified against the pattern as it stands on main:

command flagged
<cmd> > out.txt yes
<cmd> 2>out.txt yes
<cmd> 1>file yes
<cmd> >> append.txt no

Why it matters

Append is a file write. It creates the file when absent and grows it when present, so it is
squarely inside what the redirect check exists to catch — the guard's own message for the >
case is "shell output redirection (may overwrite a file)", and appending to a file the operator
did not intend to touch is the same class of accident.

The gap is also the more dangerous direction for this guard: a false negative is silent, whereas
the false positives tracked in #2615 and #2671 are at least visible as noise.

Suggested fix

Match the append form explicitly rather than widening the existing lookahead, which is load-bearing
for the stream-merge exclusion (2>&1) added in #2627 and the $null-discard exclusion in #2671.
Both of those exclusions must keep working; >> needs to be recognized without reopening either.

Care is needed on two adjacent forms so the fix does not over-correct:

Test coverage to add

In plugins/disk-hygiene/skills/clean/scripts/test_hygiene.py, alongside the existing
redirect tests: assert that >> append.txt, 2>>err.txt, and *>>all.txt produce a mutation
verdict, and that >> $null does not.

Provenance

Found while implementing #2671 (the $null-discard follow-up to #2615). It is pre-existing on
main, orthogonal to that change, and was deliberately left out of that PR rather than folded in.

Related

No linked issue: this report opens the issue rather than closing one.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions