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
29 changes: 23 additions & 6 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,34 @@ priorities.
as the v0.3 roadmap and cross-link issue #71 control flow and issue #69
shared native argument-fragment classification without merging their
scopes.
- [ ] Complete OpenSpec task group 1: lock the additive public type names,
compatibility projection, fixed analysis bounds, and supported-construct
matrix before production implementation.
- [x] Add a versioned pre-implementation design corpus with paired Bash and
PowerShell representative, boundary, and adversarial cases. The validator
rejects schema drift, checks references and command ordering, confirms
every `current` expectation against the v0.2 parsers, and includes the
files in the PII audit. Corpus review established that command role must
be immediate while ancestry remains compositional, occurrence
completeness is independent of value precision, and PowerShell authored
parameter classification must remain distinct from effective values. The
paired 32/33-candidate boundary cases lock finite-versus-unknown behavior.
- [x] Lock OpenSpec task-group decisions 1.1–1.5 and 1.8: exact public type
candidates and safe defaults, in-memory `Clause` identity, fixed 32/16/5
analysis limits, separate Bash and PowerShell grammar matrices, static
pattern-cover rules, divergent-cwd fallback, deferred forms, project
context, and the preimplementation consumer-guide migration contract.
- [ ] Complete OpenSpec tasks 1.6–1.7 in the public-API implementation PR:
synchronize the accepted shared and PowerShell contracts into
`SPEC.md` / `SPEC.POWERSHELL.md` together with source and snapshot tests
so the repository authority never intentionally drifts from the assembly.
- [ ] Implement [issue #69](https://github.com/Aaronontheweb/ShellSyntaxTree/issues/69)
as the first behavior-preserving preparation after contract lock.
- [ ] Add the structural and command-occurrence projections for the existing
grammar before enabling any control-flow construct.
- [ ] 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.
- [ ] Preserve the existing Bash heredoc grammar, fix quoted-delimiter
adjacency, expose body/delimiter/expansion/completeness facts, and add a
separately tested Bash `<<<` here-string redirect slice.

---

Expand All @@ -167,9 +185,8 @@ priorities.
composed helper.
- Windows `cmd` parser.
- Source-mapping (line/column on AST nodes) — only if an IDE consumer asks.
- Heredoc body preservation and process substitution are separately gated
issue #72 tasks backed by production need; Bash function definitions remain
deferred until a consumer need surfaces.
- Process substitution remains a separately gated issue #72 task; Bash
function definitions remain deferred until a consumer need surfaces.

## Parked

Expand Down
34 changes: 30 additions & 4 deletions PROJECT_CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ zero-native-deps .NET parser sized to what security gates actually need.

## Scope Discipline

### v0.2 (current prerelease line)
### v0.2 (current stable line)

- Bash and PowerShell 7 pipeline parsing ship behind the shared
`IShellParser` seam. Windows `cmd` remains deferred.
Expand All @@ -75,7 +75,27 @@ zero-native-deps .NET parser sized to what security gates actually need.
JSON entry parses to its expected AST, and the PowerShell corpus also passes
the live `pwsh` oracle matrix.

### Explicit non-goals
### v0.3 (contract design)

- Add a closed, strongly typed syntax-node hierarchy while retaining existing
`Clause` leaves.
- 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 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
`while` and `if` subsets independently for each shell. Shared lowering and
analysis are extracted only after both front ends prove identical behavior.
- Preserve existing Bash heredocs and add explicit body/expansion facts plus
Bash `<<<` here strings. Keep process substitution, background lists, Bash
`case`, PowerShell `switch`, arithmetic/C-style loops, and definitions
independently gated.
- Treat `openspec/changes/v0-3-structured-shell-analysis/` and its paired design
corpus as the review authority until the accepted contract is synchronized
into `SPEC.md` and `SPEC.POWERSHELL.md` with the production API change.

### v0.2 explicit non-goals

- Command execution.
- Variable expansion of any kind (we **mark** dynamic tokens, never resolve
Expand All @@ -92,12 +112,17 @@ zero-native-deps .NET parser sized to what security gates actually need.
provenance for significant clause leaves, not a lossless concrete syntax
tree.

The v0.3 scope above deliberately changes only the listed control-flow and
structural items. Execution, runtime variable expansion, full script parsing,
and IDE-grade concrete syntax remain non-goals.

### Versioning

- `0.1.0-alpha` — first publishable cut, Bash-only.
- `0.1.x` — additive (more verb table entries, more corpus, bug fixes).
- `0.2.0` — first PowerShell parser implementation; alpha and beta.1 shipped,
stable promotion pending downstream validation.
- `0.2.0` — first PowerShell parser implementation; stable.
- `0.3.0` — additive structured syntax, complete command occurrences, explicit
redirect semantics, and bounded control-flow analysis for both shells.
- `1.0.0` — at least one external consumer beyond Netclaw ships against it
without finding API gaps.

Expand Down Expand Up @@ -163,6 +188,7 @@ Per SPEC §17, all of the following must be true:
| Library source | `src/ShellSyntaxTree/` |
| Tests + corpus | `tests/ShellSyntaxTree.Tests/` |
| Corpus entries | `tests/ShellSyntaxTree.Tests/Corpus/{bash,powershell}/*.json` |
| v0.3 design corpus | `tests/ShellSyntaxTree.Tests/DesignCorpus/v0.3/{bash,powershell}.json` |
| The contracts | `SPEC.md`, `SPEC.POWERSHELL.md` |
| Consumer guide | `docs/CONSUMER_GUIDE.md` |
| Active work plan | `IMPLEMENTATION_PLAN.md` |
Expand Down
7 changes: 7 additions & 0 deletions TOOLING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ directory, routes each entry to the matching parser (`bash/` → `BashParser`,
gate — it feeds every PowerShell corpus input to real `pwsh` and enforces
the oracle matrix.

`tests/ShellSyntaxTree.Tests/DesignCorpus/v0.3/` is a separate,
pre-implementation contract corpus. Its focused validator rejects unknown JSON
members, checks syntax/occurrence references and security invariants, and
compares each recorded `current` result with the real v0.2 parser. Design cases
move into the executable `Corpus/<shell>/` only when the corresponding v0.3 API
and parser slice exists. The PII audit scans both corpus trees.

### PwshCorpusTool

`tools/PwshCorpusTool` is the PowerShell corpus authoring aid
Expand Down
51 changes: 51 additions & 0 deletions docs/CONSUMER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,57 @@ return GateDecision.Allow();
The example returns on the first non-allow result for brevity. A real UI may
collect every clause decision so the operator can see the complete command.

## Planned v0.3 migration contract

> This section describes the locked v0.3 design and is not an API available in
> the current v0.2 package. The production example above remains correct until
> a v0.3 prerelease ships.

v0.3 adds `ParsedCommand.Commands` as the authorization projection and
`ParsedCommand.Syntax` as the typed display/analysis tree. The migration rules
are:

1. Check `IsUnparseable` first. An unparseable result has empty `Commands` and
`Clauses`; any partial `Syntax` is diagnostic only.
2. Authorize every `CommandOccurrence`, including iterator, condition, branch,
substitution, and loop-body commands. Do not recursively walk `Syntax` to
discover commands.
3. Require `CommandOccurrence.IsComplete`, a recognized `ImmediateRole`, and a
static command identity before considering approval reuse.
4. Preserve authored PowerShell parameter/argument classification, then apply
shell binding and executable-specific grammar to every exact or finite
effective value. A value that begins with `-` can affect a native command;
it does not retroactively become a PowerShell cmdlet parameter token.
5. Evaluate every redirect through its explicit operation, source, target,
path relevance, and completeness. Do not infer descriptor safety from raw
prefixes.
6. Prompt or deny when an unknown value can affect identity, options, path
scope, cwd, or redirects. A structurally complete occurrence may still have
an unknown value; those are separate facts.

Heredoc and Bash here-string bodies are stdin data, not implicit child commands
or filesystem paths. Authorize any command substitutions surfaced from an
expanding heredoc as normal occurrences, then let executable-specific policy
decide whether the remaining data matters. Complete literal data need not cause
a prompt merely because it uses `<<`, `<<-`, or `<<<`; unknown data passed to a
receiver that interprets stdin as code remains policy-sensitive and fails
closed.

`ParsedCommand.Clauses` remains as a conservative v0.2 compatibility
projection during migration. For a successful result, the syntax leaf,
occurrence, and compatibility projection share the same in-memory `Clause`
instance. Nested authored commands are flattened in source order, no operator
is invented across structural boundaries, and loop variables remain authored
as dynamic values rather than being silently substituted into compatibility
records.

The new records change generated equality, hashing, `ToString()`, and default
serialization output. ShellSyntaxTree does not promise a stable serialized
wire format for its closed polymorphic syntax family. Consumers that persist
results should own a versioned DTO or explicit serializer mapping. The full
compiling v0.3 consumer example replaces this preview when the prerelease API
lands.

## Choosing a command identity

For PowerShell aliases, prefer the canonical cmdlet identity while retaining
Expand Down
Loading