From 1e2a0c330c221539d569c54e2d053e9d8c346a9c Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Sat, 8 Aug 2026 16:18:22 +0000 Subject: [PATCH] Prepare 0.3.0-alpha release --- .github/workflows/publish_nuget.yml | 19 +++++++++---------- AGENTS.md | 2 +- Directory.Build.props | 3 ++- IMPLEMENTATION_PLAN.md | 4 ++++ RELEASE_NOTES.md | 29 +++++++++++++++++++++++++++++ SPEC.md | 7 ++++--- TOOLING.md | 6 +++--- 7 files changed, 52 insertions(+), 18 deletions(-) diff --git a/.github/workflows/publish_nuget.yml b/.github/workflows/publish_nuget.yml index 289fc77..827a751 100644 --- a/.github/workflows/publish_nuget.yml +++ b/.github/workflows/publish_nuget.yml @@ -80,21 +80,20 @@ jobs: - name: "Extract latest release notes" shell: pwsh run: | - # RELEASE_NOTES.md uses `#### X.Y.Z[-suffix] ####` per-section - # headings. Capture only the BODY of the first section (no heading) - # so the GitHub release page doesn't duplicate the version string in - # both the title and the first line of the body, and so a stale - # hand-typed date in the heading doesn't fight the published date - # GitHub renders automatically. + # Select the pushed version, not the first section. An Unreleased + # section can remain at the top without changing the published body. if (-not (Test-Path RELEASE_NOTES.md)) { - "No release notes available." | Set-Content RELEASE_NOTES_LATEST.md - exit 0 + Write-Error "RELEASE_NOTES.md does not exist." + exit 1 } $content = Get-Content RELEASE_NOTES.md -Raw - if ($content -match '(?s)####[^\r\n]*\r?\n+(.+?)(?=\r?\n####|\z)') { + $version = [regex]::Escape($env:PACKAGE_VERSION) + $pattern = "(?ms)^####\s+$version(?=\s|#|\r?$)[^\r\n]*\r?\n+(.+?)(?=^####|\z)" + if ($content -match $pattern) { $Matches[1].Trim() | Set-Content RELEASE_NOTES_LATEST.md } else { - $content | Set-Content RELEASE_NOTES_LATEST.md + Write-Error "RELEASE_NOTES.md has no section for $env:PACKAGE_VERSION." + exit 1 } - name: "Create GitHub release" diff --git a/AGENTS.md b/AGENTS.md index f8bfe18..be78b75 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -203,5 +203,5 @@ dotnet test -c Release dotnet pack -c Release -o ./bin/nuget # Cut a release (manual, then push the tag) -git tag v0.1.0-alpha && git push origin v0.1.0-alpha +git tag 0.3.0-alpha && git push origin 0.3.0-alpha ``` diff --git a/Directory.Build.props b/Directory.Build.props index 8722f5e..47cd076 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,7 +7,8 @@ latest enable true - 0.2.0 + 0.3.0 + alpha diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index e11e97c..d8653ff 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -499,6 +499,10 @@ priorities. set does not support `-AsJob`. - [ ] Complete the stable-v0.3 Bash `for ... in` and PowerShell `foreach` vertical slices without gating release on a shared-analysis refactor. +- [ ] Publish `0.3.0-alpha` for the Netclaw migration gate. The release branch + sets matching package metadata, release notes, and the bare SemVer tag + contract. Mark this complete only after the tag workflow publishes the + package and GitHub prerelease. - [ ] Build on the delivered bounded Bash heredoc grammar and quoted-delimiter adjacency by exposing public body/delimiter/expansion/completeness facts, then add a separately tested Bash `<<<` here-string redirect slice. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 02dc1a0..3d39d7b 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,34 @@ #### Unreleased #### +#### 0.3.0-alpha 2026-08-08 #### + +This prerelease exposes the v0.3 structured-analysis API for Netclaw +integration. It keeps the v0.2 compatibility projection for existing +consumers. Unknown or unsupported forms continue to fail closed. + +## Added + +- Added `ParsedCommand.Syntax` and `ParsedCommand.Commands`. Consumers can now + inspect every supported command occurrence in nested shell structure. +- Added typed syntax nodes, occurrence roles, ancestry, completeness facts, + value domains, and explicit redirect analysis. +- Added bounded Bash `for ... in` and PowerShell `foreach` analysis. Exact and + finite loop values require the documented isolated initial-state modes. +- Added command-substitution and PowerShell execution-region discovery for the + supported v0.3 grammar. +- Added explicit file, stream, and descriptor redirect facts. Static descriptor + operations no longer require a consumer to infer safety from raw text. + +## Compatibility and security + +- Kept all v0.2 `ParsedCommand.Clauses`, `Clause`, `Arg`, and `Redirect` + members. The compatibility projection remains conservative. +- Kept incomplete occurrences, unknown values, dynamic command identities, + and unsupported execution-bearing syntax fail closed. +- The corpus now contains 268 Bash cases and 417 PowerShell cases. Both corpora + pass the PII audit. Every PowerShell input has a real-`pwsh` parse check, + and targeted real-Bash tests pin supported Bash semantics. + #### 0.2.0 2026-08-05 #### This stable release includes all behavior and API surface from the diff --git a/SPEC.md b/SPEC.md index b8494e5..12fbcfe 100644 --- a/SPEC.md +++ b/SPEC.md @@ -2451,7 +2451,8 @@ The repo template already has: Adapt for ShellSyntaxTree: -- **Trigger NuGet publish on tag pattern `v*.*.*`** (e.g. `v0.1.0-alpha`). +- **Trigger NuGet publish on a bare SemVer tag** (for example, + `0.3.0-alpha`). A leading `v` is invalid. - **Test job** runs the corpus runner plus all unit tests. - **PII audit job** runs the sanitization-pattern scan over `tests/ShellSyntaxTree.Tests/Corpus/`. @@ -2521,7 +2522,7 @@ A natural order for the implementer: covering each section. Iterate parser to make all pass. 13. **Sanitize and seed from real logs** (§14) — script + manual review. Add 50-100 more corpus entries. -14. **Wire CI** (§15). Tag v0.1.0-alpha when corpus is green and PII audit +14. **Wire CI** (§15). Tag `0.1.0-alpha` when the corpus is green and the PII audit passes. Estimated implementation effort: 600-800 LOC of source + 400-600 LOC of @@ -2544,7 +2545,7 @@ v0.1.0-alpha ships when **all** of the following hold: 3. ✅ Corpus has at least 105 entries spanning the categories in §13. 4. ✅ PII audit scan over `tests/ShellSyntaxTree.Tests/Corpus/bash/*.json` finds zero hits. 5. ✅ `dotnet test` runs on PR via GitHub Actions and passes. -6. ✅ Tagging `v0.1.0-alpha` triggers `publish_nuget.yml` and the package +6. ✅ Tagging `0.1.0-alpha` triggers `publish_nuget.yml` and the package appears on nuget.org. 7. ✅ Netclaw can consume the package via `` and the `IShellParser` resolves at runtime in Netclaw's DI container. diff --git a/TOOLING.md b/TOOLING.md index 3697d92..c6658e5 100644 --- a/TOOLING.md +++ b/TOOLING.md @@ -66,7 +66,7 @@ checked-in corpus. |---|---|---| | `git` | shell | everything | | `gh` CLI | shell | issues, PRs, releases, tag pushes | -| GitHub Actions | `.github/workflows/` | `pr_validation.yml` (build + test + pack on PR/push), `publish_nuget.yml` (pack + push + release on `v*.*.*` tags) | +| GitHub Actions | `.github/workflows/` | `pr_validation.yml` (build + test + pack on PR/push), `publish_nuget.yml` (validates bare SemVer tags, then packs, pushes, and releases) | | GitHub Dependabot | `.github/dependabot.yml` | NuGet bumps | ## NuGet @@ -97,8 +97,8 @@ Required configuration (one-time, on `nuget.org`): Required configuration (one-time, in repo settings): 1. **Settings → Environments → New environment** → name `nuget`. - Optional protection: restrict deployment to tags matching - `v*.*.*`. + Optional protection: restrict deployment to bare SemVer release tags such + as `0.3.0-alpha`. 2. **Settings → Secrets and variables → Actions → New repository secret** — `NUGET_USER` set to the nuget.org account username that owns the package. The legacy `NUGET_KEY` secret can be