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
18 changes: 18 additions & 0 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,24 @@ priorities.
call-operator, dynamic-identity, and host-wrapper positions, with
current-scope state propagation and bounded expression rejection pinned
by the 372-entry executable corpus.
- [ ] Deliver typed PowerShell script-block execution regions before calling
tasks 7.5-7.7 complete. The corrected contract adds an execution-region
syntax node with independent origin, phase, timing, and cardinality rather than a
false shared/isolated scope flag. The inert additive public API skeleton,
enum/default snapshots, recorded local PowerShell probe evidence, and
design-corpus categories are delivered; no parser emits a region yet and
automated execution-region oracle coverage remains in task 7.7. Continue in
small slices: projection; pinned receiver/parameter binding including
ForEach-Object multi-block phases; direct `&` / `.` and synchronous
current-runspace callbacks; child process/runspace jobs and parallel
blocks; deferred breakpoint/event/completion actions; then unknown
receiver and nested/adversarial matrices. Preserve script blocks proved
to be data as opaque values, expose ambiguous bodies with incomplete
facts, and fail atomically when any potentially executable interior is
unsupported. Local PowerShell 7.6.4 probes pin variable-versus-location
independence, semantic phase order, child process/runspace boundaries,
registration-versus-trigger timing, and the fact that the in-process
`Invoke-Command` parameter set does not support `-AsJob`.
- [ ] Deliver Bash `for ... in` and PowerShell `foreach` as the first two
language-specific vertical slices, then extract only the shared analysis
proven by both implementations.
Expand Down
6 changes: 6 additions & 0 deletions PROJECT_CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ zero-native-deps .NET parser sized to what security gates actually need.
- Add a library-owned command-occurrence projection for security consumers so
every potentially executable iterator, condition, branch, substitution, and
body command is evaluated exactly once.
- Add typed PowerShell execution regions for direct call/dot-source blocks,
synchronous callbacks, jobs/parallel runspaces, initialization, and deferred
actions. Public origin/phase/timing/cardinality facts remain separate from
shell-specific variable, location, command-resolution, runspace, and process
state analysis; proved script-block data stays opaque and unknown receivers
conservatively expose incomplete bodies.
- Add fixed, non-executing value and state analysis: at most 32 candidates, at
most 16 structural container levels, and the existing wrapper depth of 5.
- Deliver Bash `for ... in` and PowerShell `foreach` first, then the locked
Expand Down
137 changes: 111 additions & 26 deletions SPEC.POWERSHELL.md

Large diffs are not rendered by default.

95 changes: 89 additions & 6 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,14 @@ public sealed record ConditionLoopSyntax : ShellSyntaxNode { ... }
public sealed record ConditionalSyntax : ShellSyntaxNode { ... }
public sealed record ConditionalBranchSyntax : ShellSyntaxNode { ... }
public sealed record CommandSubstitutionSyntax : ShellSyntaxNode { ... }
public sealed record ExecutionRegionSyntax : ShellSyntaxNode { ... }
public enum ShellSyntaxKind { ... }
public enum ShellGroupKind { ... }
public enum ConditionLoopKind { ... }
public enum ExecutionRegionOrigin { ... }
public enum ExecutionRegionPhase { ... }
public enum ExecutionRegionTiming { ... }
public enum ExecutionRegionCardinality { ... }

// v0.3 authorization and bounded-analysis projections — see §3.
public sealed record CommandOccurrence { ... }
Expand Down Expand Up @@ -346,7 +351,9 @@ positional argument: the retained v0.2 `Arg.IsFlag` contract recognizes only
an ASCII `-`, so normalizing the authored `Raw` spelling would either lose
provenance or require a breaking API change. Unsupported module-qualified
cmdlets are likewise rejected inside structural regions, not only in a flat
command; the existing module-qualified `Invoke-Expression` exception remains.
command. The existing module-qualified `Invoke-Expression` exception and the
version-pinned PowerShell execution-region receiver catalog are the only
specified exceptions.

For a successful result, every authored simple command appears once in
`Syntax`, once in `Commands`, and once in `Clauses`, with all three projections
Expand Down Expand Up @@ -389,6 +396,7 @@ public enum ShellSyntaxKind
Conditional,
ConditionalBranch,
CommandSubstitution,
ExecutionRegion,
}

public sealed record ShellBlockSyntax : ShellSyntaxNode
Expand All @@ -402,6 +410,7 @@ public sealed record SimpleCommandSyntax : ShellSyntaxNode
public override ShellSyntaxKind Kind => ShellSyntaxKind.SimpleCommand;
public Clause Clause { get; init; } = new();
public IReadOnlyList<CommandSubstitutionSyntax> Substitutions { get; init; } = [];
public IReadOnlyList<ExecutionRegionSyntax> ExecutionRegions { get; init; } = [];
}

public sealed record PipelineSyntax : ShellSyntaxNode
Expand Down Expand Up @@ -492,6 +501,54 @@ public sealed record CommandSubstitutionSyntax : ShellSyntaxNode
public override ShellSyntaxKind Kind => ShellSyntaxKind.CommandSubstitution;
public ShellBlockSyntax Body { get; init; } = new();
}

public sealed record ExecutionRegionSyntax : ShellSyntaxNode
{
public override ShellSyntaxKind Kind => ShellSyntaxKind.ExecutionRegion;
public ExecutionRegionOrigin Origin { get; init; }
public int? HostClauseElementIndex { get; init; }
public ExecutionRegionPhase Phase { get; init; }
public ExecutionRegionTiming Timing { get; init; }
public ExecutionRegionCardinality Cardinality { get; init; }
public ShellBlockSyntax Body { get; init; } = new();
}

public enum ExecutionRegionOrigin
{
Unknown,
DirectCall,
DotSource,
CommandArgument,
}

public enum ExecutionRegionPhase
{
Unknown,
Main,
Initialization,
Begin,
Process,
End,
Filter,
Action,
Completion,
}

public enum ExecutionRegionTiming
{
Unknown,
Synchronous,
Concurrent,
Deferred,
}

public enum ExecutionRegionCardinality
{
Unknown,
Once,
OncePerInputObject,
ZeroOrMore,
}
```

`ForEachSyntax` shares proved execution structure only. `Iterable.Raw` keeps
Expand Down Expand Up @@ -527,6 +584,7 @@ public enum CommandOccurrenceRole
LoopBody,
Branch,
Substitution,
ExecutionRegion,
}

public sealed record CommandAncestryFrame
Expand All @@ -550,6 +608,7 @@ public enum CommandAncestryRegion
Condition,
Branch,
Substitution,
ExecutionRegion,
}

public sealed record EffectiveArgument
Expand Down Expand Up @@ -596,10 +655,32 @@ preserves nesting: a substitution inside an inner simple command belongs to
that inner command, not to the outer command or a side table. `Clause` remains
the unchanged v0.2 compatibility leaf and retains the authored dynamic value.

`SimpleCommandSyntax.ExecutionRegions` owns each completely delimited body
that a proved or conservatively unknown command binding may execute. The
unchanged host `Clause` retains its authored script-block `DynamicSkip`
argument. A direct PowerShell `& {}` or `. {}` region appears as a statement,
carries `Origin=DirectCall` or `Origin=DotSource`, has
`HostClauseElementIndex=null`, and creates no synthetic occurrence for the
invocation operator. A command-owned region carries `Origin=CommandArgument`
and the non-negative index of its script-block token in the host
`Clause.Elements`. Consumers use `Origin`, rather than reparsing source text,
to distinguish the different direct-invocation state semantics.

Execution-region origin, phase, timing, and cardinality are independent
structural facts. Attached regions retain authored script-block order even when a
shell-specific analyzer schedules Begin/Process/End or initialization/main in
another semantic order. `Synchronous`, `Concurrent`, and `Deferred` do not
claim variable, cwd, command-resolution, runspace, or process scope. Those
dimensions remain shell-specific analysis because PowerShell can isolate
ordinary variable assignment while sharing location. Unknown enum values fail
closed.

The canonical `Commands` and compatibility `Clauses` projections use these
deterministic ordering rules: disjoint executable regions follow authored
source order; an enclosed substitution precedes its containing command;
nested substitutions are emitted innermost first; and nodes without comparable
nested substitutions are emitted innermost first; a command-owned execution
region follows its host and sibling regions retain authored order; and nodes
without comparable
outer source spans use their containing structural collection order. Thus
`rm "$(find /tmp)"` projects `find`, then `rm`, exactly once each.
Each substitution ancestry frame uses `Region=Substitution` and its authored
Expand All @@ -612,13 +693,14 @@ next node on the path. The root block uses `Root`; non-root blocks and command
lists use `Statement`; pipelines use `PipelineStage`; groups use `GroupBody`;
foreach nodes use `Iterator` or `LoopBody`; condition loops use `Condition` or
`LoopBody`; conditionals use `Branch`; conditional-branch nodes use
`Condition` or `Branch`; and command substitutions use `Substitution`.
`Condition` or `Branch`; command substitutions use `Substitution`; and
execution regions use `ExecutionRegion`.
Repeated children use their zero-based authored index. The `else` child uses
the branch count, placing it after every condition/body pair. Frame source
ranges belong to the ancestor. Blocks, command lists, and groups retain the
incoming immediate role; pipeline stages, iterator/body regions,
condition/body regions, branches, and substitutions replace it with their
nearer execution role.
condition/body regions, branches, substitutions, and execution regions replace
it with their nearer execution role.

Projection accepts only a parser-owned tree: a syntax-node or `Clause`
reference cannot appear at two authored positions, node and fragment spans are
Expand Down Expand Up @@ -647,7 +729,8 @@ The parser does not execute commands, inspect runtime variables, enumerate the
filesystem, or truncate an over-limit set and call it complete. A result with
33 or more candidates becomes `Unknown`. Structural depth starts at zero for
the root and increments on foreach loops, condition loops, conditionals,
groups, and command substitutions; blocks, lists, pipelines, branches, and
groups, command substitutions, and execution regions; blocks, lists,
pipelines, branches, and
simple-command leaves do not independently increment it. Exceeding 16
structural containers or 5 decoded-command wrapper recursions makes the entire
result unparseable.
Expand Down
Loading