Skip to content

Use native PowerShell on Windows - #1848

Merged
Aaronontheweb merged 4 commits into
devfrom
feature/native-windows-powershell-activation
Aug 10, 2026
Merged

Use native PowerShell on Windows#1848
Aaronontheweb merged 4 commits into
devfrom
feature/native-windows-powershell-activation

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Collaborator

Summary

  • Select one immutable shell environment during daemon composition.
  • Use Bash on Unix hosts and native PowerShell on Windows hosts.
  • Prefer supported PowerShell 7.6 and use Windows PowerShell 5.1 as the fallback.
  • Route execution, analysis, policy, approvals, jobs, and model context through the same environment.
  • Keep Bash and PowerShell payloads in separate grammar boundaries.
  • Preserve the public v0.2 compatibility surface.

Security

  • Deny recursive root removal before approval checks.
  • Deny process termination and PowerShell elevation before approval checks.
  • Reject incomplete, dynamic, and dialect-unknown commands for stored grants and safe-verb access.
  • Reuse one authorized analysis for each dispatch.
  • Keep direct shell calls fail closed.

Evidence

  • The adversarial review passed after all findings were fixed.
  • The Release build passed with zero warnings and zero errors.
  • The full solution test suite passed.
  • Security tests passed: 827 of 827.
  • Focused actor tests passed: 327, with one native Windows test skipped on Linux.
  • Resolver tests passed: 14 of 14.
  • Format, header, Slopwatch, diff, and strict OpenSpec checks passed.
  • The behavioral evaluation could not run because provider settings were absent. This result is blocked evidence, not a pass.

OpenSpec

Change: native-windows-powershell-host

Three tasks remain. Windows CI must supply native host evidence. The final flow must merge, verify, sync, and archive the change.

@Aaronontheweb
Aaronontheweb enabled auto-merge (squash) August 10, 2026 09:58
Comment on lines +156 to +164
foreach (var unit in ExtractApprovalUnitsViaAnalysis(analysis))
{
var normalized = ShellTokenizer.NormalizeApprovalUnit(unit, workingDirectory);
var normalized = ShellTokenizer.NormalizeApprovalUnit(
unit,
workingDirectory,
Environment.PathStyle);
if (!string.IsNullOrEmpty(normalized))
patterns.Add(normalized);
});
}
Comment on lines +126 to +134
catch (Exception ex)
{
ReportCompletion(
BackgroundJobStatus.Failed,
-1,
$"Failed to start shell '{_environment.ExecutableName}' "
+ $"at '{_environment.ExecutablePath}': {ex.Message}");
return;
}
Comment on lines +45 to +49
var executablePath = Path.Combine(
systemDirectory,
"WindowsPowerShell",
"v1.0",
"powershell.exe");
break;
}
{
var linkDir = Path.Combine(scratch, "link");
// Lexically this path lives in scratch/link, outside any
// denied root — only segment-walk symlink resolution
// catches it.
viaLink = Path.Combine(linkDir, "netclaw.json");
// linkA -> linkB -> deniedDir. A resolver that only
// follows one hop would stop at linkB; the walk must
// reach the final real target.
var linkB = Path.Combine(scratch, "linkB");
// follows one hop would stop at linkB; the walk must
// reach the final real target.
var linkB = Path.Combine(scratch, "linkB");
var linkA = Path.Combine(scratch, "linkA");
createdLinks.Add(linkB);
createdLinks.Add(linkA);

viaLink = Path.Combine(linkA, "netclaw.json");
[InlineData(@"Remove-Item -LiteralPath FileSystem::C:\ -R -Confirm:$false")]
[InlineData(@"Remove-Item -Path:C:\ -Recurse")]
[InlineData(@"ri C:\ -Recurse")]
public void Native_power_shell_denies_recursive_root_removal_without_force(string command)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This and the test below it are going to need to be revisited from a safety perspective

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant