Skip to content

Add platform-aware Bash and PowerShell execution context - #1698

Closed
Aaronontheweb wants to merge 6 commits into
netclaw-dev:devfrom
Aaronontheweb:feat/canonical-bash-powershell-execution
Closed

Add platform-aware Bash and PowerShell execution context#1698
Aaronontheweb wants to merge 6 commits into
netclaw-dev:devfrom
Aaronontheweb:feat/canonical-bash-powershell-execution

Conversation

@Aaronontheweb

@Aaronontheweb Aaronontheweb commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • make ShellSyntaxTree the canonical structural authority for Bash and PowerShell commands
  • derive one immutable execution environment and select Bash or PowerShell 7 consistently
  • inject platform, shell, and grammar hints into the working context while preserving the cache-stable tail
  • harden command policy, approval matching, and trust-zone checks for wrappers, aliases, redirects, and dynamic syntax
  • update embedded agent guidance, the operations system skill, specifications, and tooling documentation

Security behavior

  • recursively analyzes supported wrapper commands before approval or trust-zone decisions
  • fails closed for unresolved dynamic operands and redirects
  • rejects unsupported shell pivots and encoded PowerShell payloads
  • canonicalizes PowerShell aliases, module-qualified verbs, and unambiguous parameter abbreviations
  • scopes static redirection targets before execution

Validation

  • 6,071 tests passed; 15 environment-dependent tests skipped
  • focused shell security suite: 106 passed
  • adversarial review and follow-up re-review: no remaining actionable findings
  • dotnet slopwatch analyze: 0 issues
  • file-header verification: passed
  • git diff --check: passed
  • OpenSpec strict validation: passed

Known limitation

The provider-backed behavioral eval was not run because NETCLAW_EVAL_PROVIDER_TYPE, NETCLAW_EVAL_PROVIDER_ENDPOINT, and NETCLAW_EVAL_MODEL_ID are not configured in this environment. OpenSpec task 4.4 remains unchecked accordingly.

Issues resolved

Closes #1693
Closes #964
Closes #965
Closes #899

@Aaronontheweb
Aaronontheweb requested a review from Copilot July 19, 2026 00:20
@Aaronontheweb Aaronontheweb added tools Issues related to agent tools: file_read, web_search, shell_execute, image processing, etc. security Security-related changes labels Jul 19, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes shell execution and shell security policy platform-aware and grammar-consistent by introducing a single canonical execution environment (Bash on Unix-like hosts, PowerShell 7 on Windows) and routing parsing, approvals, trust-zone checks, and process startup through the same ShellSyntaxTree-backed structural authority.

Changes:

  • Introduce ShellExecutionEnvironment as the immutable canonical source of platform/shell/grammar/path-style and use it across execution, parsing, security policy, and working-context grounding.
  • Harden shell security and approval logic to evaluate every executable pipeline clause (including tails) and treat dynamic/unresolved syntax as non-persistable (messy) for approvals.
  • Update documentation/specs/evals and operational guidance to reflect the canonical shell selection (including the Windows PowerShell 7 prerequisite).

Reviewed changes

Copilot reviewed 62 out of 62 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
TOOLING.md Documents canonical shell selection and PowerShell 7 prerequisite.
src/Netclaw.Security/ShellTokenizer.cs Expands legacy segment extraction to include pipeline clauses.
src/Netclaw.Security/ShellExecutionEnvironment.cs Adds canonical shell environment + analyzer used across security/execution.
src/Netclaw.Security/ShellCommandPolicy.cs Routes hard-deny evaluation through canonical parsing and adds PowerShell-specific denies.
src/Netclaw.Security/ShellApprovalSemantics.cs Improves inner-command extraction scanning for wrapper flags.
src/Netclaw.Security/SecurityServiceExtensions.cs Registers canonical environment + matching parser for DI.
src/Netclaw.Security/IToolApprovalMatcher.cs Reworks shell approval matching to use canonical parsing and pipeline-wide candidates.
src/Netclaw.Security.Tests/ShellSyntaxTreeIntegrationTests.cs Adds parser integration coverage for wrappers, aliases, and dynamic PowerShell verbs.
src/Netclaw.Security.Tests/ShellCommandPolicyTests.cs Adds regressions for pipeline tails, PowerShell canonical verbs, wrappers, and missing-shell behavior.
src/Netclaw.Security.Tests/ShellCommandPolicyOverrideTests.cs Updates overrides tests for required ShellExecutionEnvironment injection.
src/Netclaw.Security.Tests/ShellApprovalMatcherTests.cs Updates matcher tests for pipeline clause candidates and PowerShell behavior.
src/Netclaw.Security.Tests/ShellApprovalMatcherMultilineTests.cs Expands multiline tests to apply cross-platform via canonical parsing.
src/Netclaw.Daemon/Program.cs Wires canonical environment + parser into daemon DI and tool policy construction.
src/Netclaw.Daemon.Tests/Mcp/ToolIndexUpdaterTests.cs Updates test wiring for required shell command policy environment.
src/Netclaw.Configuration/SafeVerbs/safe-verbs.windows.json Clarifies Windows safe verbs match PowerShell canonical verb extraction.
src/Netclaw.Configuration/Resources/AGENTS.md Instructs agents to follow [working-context].execution_environment grammar/path-style.
src/Netclaw.Configuration.Tests/FileSystemPromptProviderAudienceTests.cs Verifies shell environment guidance appears only for non-Public audiences.
src/Netclaw.Cli.Tests/Tui/ChatPageTests.cs Updates TUI tests for required shell policy injection.
src/Netclaw.Actors/Tools/ToolAccessPolicy.cs Makes shell policy mandatory and uses canonical parsing for trust-zone/path checks and approvals.
src/Netclaw.Actors/Tools/ShellTool.cs Executes through canonical shell + arguments, adds missing-shell error, updates cwd hints.
src/Netclaw.Actors/Tools/DispatchingToolExecutor.cs Updates default executor wiring for required shell environment.
src/Netclaw.Actors/SubAgents/SubAgentActor.cs Updates sub-agent wiring for required shell environment.
src/Netclaw.Actors/Sessions/WorkingContextSnapshot.cs Adds execution_environment to working-context snapshots (Personal-only), with inspector wiring.
src/Netclaw.Actors/Jobs/BackgroundJobManagerActor.cs Threads canonical shell environment into job execution actor creation.
src/Netclaw.Actors/Jobs/BackgroundJobExecutionActor.cs Executes background jobs via canonical shell + arguments and missing-shell failure behavior.
src/Netclaw.Actors.Tests/Tools/ToolRegistryTests.cs Updates tool registry tests for required shell policy injection.
src/Netclaw.Actors.Tests/Tools/ToolArgumentValidatorTests.cs Updates validator tests for required shell policy injection.
src/Netclaw.Actors.Tests/Tools/ToolApprovalGateTests.cs Adds pipeline-tail/trust-zone regressions and updates wiring for canonical environment.
src/Netclaw.Actors.Tests/Tools/SkillToolTests.cs Updates sub-agent/test DI to include execution-environment inspector.
src/Netclaw.Actors.Tests/Tools/ShellToolTests.cs Adds PowerShell execution tests and missing-shell “no fallback” assertions.
src/Netclaw.Actors.Tests/Tools/ShellToolStreamingTests.cs Updates streaming tests for PowerShell equivalents and required policy injection.
src/Netclaw.Actors.Tests/Tools/SetWorkingDirectoryAudienceTests.cs Updates audience tests for required shell policy injection.
src/Netclaw.Actors.Tests/Tools/SearchToolsToolTests.cs Updates search tool tests for required shell policy injection.
src/Netclaw.Actors.Tests/Tools/SchedulingToolAudienceTests.cs Updates audience tests for required shell policy injection.
src/Netclaw.Actors.Tests/Tools/MetaFieldResolutionTests.cs Updates tool registry wiring for required shell policy injection.
src/Netclaw.Actors.Tests/Tools/MessyCommandOneTimeApprovalTests.cs Updates host wiring for required shell policy injection.
src/Netclaw.Actors.Tests/Tools/McpToolAudienceGrantsTests.cs Updates policy construction for required shell policy injection.
src/Netclaw.Actors.Tests/Tools/DispatchingToolExecutorTests.cs Updates executor tests for required shell policy injection and adds redirect approval regression.
src/Netclaw.Actors.Tests/SubAgents/SubAgentSpawnObservabilityTests.cs Updates snapshot provider wiring to include execution-environment inspector.
src/Netclaw.Actors.Tests/SubAgents/SubAgentSpawnerTests.cs Verifies child-run propagation includes execution environment snapshot.
src/Netclaw.Actors.Tests/SubAgents/SubAgentActorTests.cs Updates approval-required policy construction for required shell policy injection.
src/Netclaw.Actors.Tests/SubAgents/SpawnAgentStreamingTests.cs Updates spawn streaming tests for required shell policy injection and env inspector.
src/Netclaw.Actors.Tests/Sessions/WorkingContextSnapshotTests.cs Adds execution-environment snapshot coverage and git failure resilience assertions.
src/Netclaw.Actors.Tests/Sessions/SubAgentSpawnIntegrationTests.cs Updates child-run grounding assertions to include execution environment.
src/Netclaw.Actors.Tests/Sessions/LlmSessionTestExtensions.cs Adds canonical environment + inspector to test DI.
src/Netclaw.Actors.Tests/Sessions/CompactionIntegrationTests.cs Ensures execution environment survives compaction and preserves cached prefix stability.
src/Netclaw.Actors.Tests/Jobs/BackgroundJobManagerActorTests.cs Updates job manager actor creation to include canonical environment.
src/Netclaw.Actors.Tests/Jobs/BackgroundJobIntegrationTests.cs Updates integration wiring for canonical environment.
src/Netclaw.Actors.Tests/Jobs/BackgroundJobExecutionActorTests.cs Adds missing-shell regression for background job execution.
openspec/changes/canonical-bash-powershell-execution/tasks.md Tracks implementation tasks for the canonical shell execution change.
openspec/changes/canonical-bash-powershell-execution/specs/netclaw-tools/spec.md Specifies canonical shell tool behavior and pipeline-wide policy requirements.
openspec/changes/canonical-bash-powershell-execution/specs/netclaw-session/spec.md Specifies execution-environment grounding in working-context with cache stability guarantees.
openspec/changes/canonical-bash-powershell-execution/specs/netclaw-agent-memory/spec.md Specifies prompt assembly guidance to consult execution environment for shell grammar.
openspec/changes/canonical-bash-powershell-execution/specs/canonical-shell-execution/spec.md Defines canonical environment and pipeline-wide structural policy requirements.
openspec/changes/canonical-bash-powershell-execution/proposal.md Documents motivation/scope and breaking change (Windows pwsh execution).
openspec/changes/canonical-bash-powershell-execution/design.md Captures design decisions, risks, and migration plan for canonical shell execution.
openspec/changes/canonical-bash-powershell-execution/.openspec.yaml Declares OpenSpec change metadata.
feeds/skills/.system/files/netclaw-operations/SKILL.md Updates operational skill guidance for execution_environment and canonical shell rules.
evals/run-evals.sh Adds eval assertion ensuring shell commands follow declared grammar.
evals/README.md Updates eval suite matrix counts for new grounding check.
docs/spec/SPEC-011-daemon-architecture.md Documents canonical shell environment usage in daemon architecture spec.
Directory.Packages.props Bumps ShellSyntaxTree dependency to 0.2.0-alpha.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +250 to +261
private static bool IsPowerShellParameterAbbreviation(string token, string parameter)
{
if (token.Length < 2 || token[0] != '-')
return false;

var name = token[1..];
var colon = name.IndexOf(':', StringComparison.Ordinal);
if (colon >= 0)
name = name[..colon];

return name.Length > 0 && parameter.StartsWith(name, StringComparison.OrdinalIgnoreCase);
}
Comment on lines +124 to +126
var mkdirHint = _environment.Grammar == ShellGrammar.PowerShell
? $"New-Item -ItemType Directory -Path '{resolvedCwd}'"
: $"mkdir -p \"{resolvedCwd}\"";
Comment on lines +347 to +349
var mkdirHint = _environment.Grammar == ShellGrammar.PowerShell
? $"New-Item -ItemType Directory -Path '{resolvedCwd}'"
: $"mkdir -p \"{resolvedCwd}\"";
Comment on lines +113 to 115
var mkdirHint = _environment.Grammar == ShellGrammar.PowerShell
? $"New-Item -ItemType Directory -Path '{_definition.WorkingDirectory}'"
: $"mkdir -p \"{_definition.WorkingDirectory}\"";
Copilot AI review requested due to automatic review settings July 27, 2026 14:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 62 out of 62 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/Netclaw.Configuration/SafeVerbs/safe-verbs.windows.json:17

  • This file says safe-verb matching is done by exact equality against the PowerShell parser’s canonical verb-chain extraction, but the list includes PowerShell aliases like "dir" and "type". ShellSyntaxTree exposes canonical verbs for those aliases (e.g., dir → Get-ChildItem, type → Get-Content), so these alias entries won’t ever match the canonical verb chain and are effectively dead / misleading.

Comment on lines +366 to +371
if (quote == ch)
{
quote = null;
current.Append(ch);
continue;
}

#### Scenario: Model receives canonical shell facts

- **GIVEN** a Personal or Team turn can use shell execution
Copilot AI review requested due to automatic review settings July 30, 2026 14:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…ndows

Add the read-only pipeline and formatting cmdlets that idiomatic PowerShell
pipelines end in — Select-Object, Sort-Object, Group-Object, Measure-Object,
Format-Table/List/Wide, Out-String, Get-Member, Compare-Object, Get-Unique,
ConvertTo/From-Json, ConvertTo/From-Csv, Write-Output, Get-Command, Get-Help,
Get-Alias — to the Windows safe-verb list so they auto-pass inside a trusted
zone instead of prompting every time.

These cmdlets can run arbitrary code only through a script-block or
calculated-property argument. The parser tags such arguments dynamic, which
marks the whole command messy and removes it from the auto-pass path, so only
their plain read-only forms ever short-circuit approval. Where-Object and
ForEach-Object are omitted because they always carry a script block.

Lock the guardrail with matcher tests (plain form stays auto-pass eligible; a
script-block argument is forced messy) and extend the safe-verb loader tests.
…safe verbs

A Windows/PowerShell security audit of the safe-verb allowlist flagged three of
the newly added verbs:

- Write-Output weaponizes the redirect-write path into an arbitrary-content
  file write (Write-Output '<bytes>' > path) that auto-approves inside a
  trusted zone.
- Get-Command can auto-import a module, running its startup code, if a
  malicious module sits on PSModulePath.
- Get-Help -Online spawns a browser and issues a network request.

Remove all three; the remaining read-only formatting and serialization verbs
are cleared by the audit. Pin the exclusions with loader-test assertions.
…olled scan

The approval matcher used a hand-written scan to flag commands too complex to
auto-approve. It matched bare bash keywords and counted brackets, so it wrongly
flagged safe commands: `echo done` was marked complex because `done` is a loop
keyword, forcing a needless prompt.

Remove that scan from the three matcher sites that drive auto-pass and
persistence (IsMessy, IsApproved, ExtractApprovalUnitsViaParser). The parser's
own analysis already runs right after each and covers real control flow,
unbalanced quotes, and dynamic operands more accurately. A regression test pins
that a control-flow keyword used as a plain argument now resolves to a clean
candidate.

The scan stays for the hard-deny fallback path, a separate concern untouched here.
…just cwd

The safe-verb short-circuit auto-approved a read-only verb whenever the process
cwd sat inside a safe-space root, without checking what the command actually
read or wrote. So `cat /etc/passwd` or `Get-ChildItem Env:` from a trusted cwd
auto-passed with no prompt, reaching files and ambient state outside the zone.

- Require every static path the command touches (arguments and redirect
  targets) to resolve inside a safe-space root before auto-approving; otherwise
  fall through to the interactive prompt. Adds ScopedShellSafeVerbPolicy.
  IsWithinSafeSpace, gated in ToolAccessPolicy via OperationStaysInSafeSpace.
- Never auto-pass a command referencing a non-filesystem PowerShell provider
  drive (Env:, HKLM:, Cert:, ...); those expose ambient state a filesystem-zone
  check cannot contain.
- Fix a pre-existing gap in TryExtractStaticPathTokens: quoted path arguments
  ("C:\x") were dropped because the leading quote broke drive-letter detection,
  so they escaped both this check and non-interactive trust-zone enforcement.
  Strip surrounding quotes and prefer the parser's resolved absolute path. This
  also fixes PowerShell_pipeline_tail_outside_trust_zone_is_denied.

Adds unit coverage for the in-zone path check and end-to-end coverage for
in-zone auto-pass, out-of-zone prompt, and provider-drive prompt.
…l host

On Windows the canonical shell is PowerShell, so tests written for Bash grammar
ran under the wrong shell and failed. Fixed genuinely — no skips, no weakened
assertions:

- Pin Bash-grammar policy/matcher tests to ShellExecutionEnvironment.Bash() so
  they exercise Bash on any host (bash -c recursion, POSIX verbs, rm -rf /,
  fork bomb, POSIX paths). Local Bash-pinned instances only; shared fields
  unchanged.
- Normalize \ vs / when asserting an extracted directory, since the parent-dir
  helper uses OS-native separators; the directory identity under test is kept.
- Real-shell run tests: on Windows write stderr via [Console]::Error.WriteLine
  (exits 0) and assert the PowerShell New-Item create-directory hint.
- Parser DI test asserts the OS-appropriate parser (PwshParser on Windows,
  BashParser otherwise); registration untouched.

Full solution green on Windows; slopwatch clean; no new skips (the 39 skips are
the pre-existing POSIX-only set).
Copilot AI review requested due to automatic review settings August 1, 2026 03:28
@Aaronontheweb
Aaronontheweb force-pushed the feat/canonical-bash-powershell-execution branch from 826f395 to 40f6f97 Compare August 1, 2026 03:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 65 out of 65 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

openspec/changes/canonical-bash-powershell-execution/specs/netclaw-session/spec.md:9

  • This scenario says a Team turn can use shell execution, but ToolAccessPolicy denies shell unless the audience is Personal ("shell_requires_personal_context"). Update this scenario text or change the implementation to match the requirement.
- **GIVEN** a Personal or Team turn can use shell execution

Comment on lines +132 to +134
var parsed = _environment.Analyze(command);
if (parsed.Failure == ShellAnalysisFailure.UnsupportedShellWrapper)
{
@Aaronontheweb

Copy link
Copy Markdown
Collaborator Author

Superseded by #1733 — rebased on upstream/dev, all commits squashed into one signed commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security Security-related changes tools Issues related to agent tools: file_read, web_search, shell_execute, image processing, etc.

Projects

None yet

2 participants