Repository navigation
Refuse scriptblock job values at runtime; tighten Lint Rules 7-9 - #4
Merged
Merged
Conversation
Invoke-ZipParallelProcessing now refuses a job whose value is a scriptblock, or holds one directly in an array or hashtable value, with a message naming the key and the [scriptblock]::Create() workaround. A -JobParams list is checked before anything runs, and each -NextJobProvider job as it's produced. The new Scenario H in the harness fails without this check. That replaces the static job-parameter matcher in Lint Rule 7, which missed several call shapes. Rule 7 now flags a scriptblock variable, or a [scriptblock]-typed parameter, passed to a .NET method or constructor, and only treats .GetNewClosure() results as scriptblocks. The new Rule 9 flags host cmdlets (Write-Host, Read-Host and others) on runspace-reachable paths. Workers share the console host, so these would bypass the console queue. The old cmdlet ban used to catch them by accident. Rules 7-9 share one traversal, and each function's file is recorded once instead of being searched for in every rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Job guard (Invoke-ZipParallelProcessing):
- Looks up to four levels down, through arrays, lists, hashtables and
[pscustomobject] properties.
- Reads each collection once per call. A collection passed by reference
to every job is checked with the first job, before any worker can be
writing to it. A collection that can't be read because something is
changing it is let through instead of failing the run.
- A refused -NextJobProvider job no longer throws mid-loop and stops
the workers already running. New jobs stop starting, the running ones
finish and report, and then the call throws.
Lint:
- Rule 7 also flags a scriptblock stored through an indexer or property
on a container the code didn't create ($cache[$k] = $sb,
$slot.Factory = { }).
- Rule 9 resolves aliases (cls, clear, oh) and flags direct
[Console]:: and $Host.UI use.
module-descriptions.md documents the console rule as a third
worker-runspace rule. The new harness and Lint assertions fail against
the previous code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Job guard (Invoke-ZipParallelProcessing): - Reads only materialized collections (ICollection, ICollection<T>, IReadOnlyCollection<T>). A lazy or consuming enumerable such as GetConsumingEnumerable() is no longer drained before the worker gets it. - Looks inside KeyValuePair and DictionaryEntry values, which were skipped along with every other value type. - Reads a [pscustomobject] shared across jobs once per call, like collections. - Lets a collection through only when it reports being modified. Any other failure to read a value now throws, naming the key. Lint: - One helper decides what counts as an assigned scriptblock literal. - Rule 7 treats a container as local only if every assignment to it creates a new one, so a store through an alias of a shared container or through a loop variable is flagged. - Rule 9 matches module-qualified names. The harness's enumeration test doubles are PowerShell classes, so the harness no longer compiles a type with Add-Type. The new harness and Lint assertions fail against the previous code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3, which was merged before this commit was pushed.
What was wrong
A code review of #3 found gaps in its new Lint Rule 7:
[scriptblock]-typed parameters, provider output withoutreturn, and the colon, inline and splatted forms of-JobParams.Write-Host/Read-Hostin worker code anymore. Workers share the console host, so these bypass the console queue.What changed
Invoke-ZipParallelProcessingrefuses a job whose value is a scriptblock, or holds one directly in an array or hashtable value (newGet-ZipJobScriptBlockKey). The error names the key and points to the workaround: pass the code as a string and build it in the worker with[scriptblock]::Create().-JobParamslist is checked before anything runs.-NextJobProviderjob is checked as it's produced.[scriptblock]parameter, passed to a .NET method or constructor from runspace-reachable code. Only.GetNewClosure()results count as scriptblocks.Write-Host,Read-Hostand others) on runspace-reachable paths, with the existingWrite-LogLineToHostexception.How it was tested
Runtime guard: new
ZipParallelProcessingharness Scenario H checks four cases that must be refused and one that must still run:Against the module without the guard, 5 of its 6 asserts fail.
Lint: sample asserts for every shape each rule flags or skips. Planting one violation per rule in a copy of the real modules makes each rule fail with the right file and line, and current
mainpasses them all.All 21 local harnesses pass.
🤖 Generated with Claude Code