Omit approved candidates from shell prompts - #1830
Conversation
| [Fact(SkipUnless = nameof(IsPosix), Skip = "POSIX-only shell directory semantics")] | ||
| public async Task Authorization_evaluation_preserves_directory_for_duplicate_verb_candidates() | ||
| { | ||
| var root = Path.Combine(Path.GetTempPath(), $"netclaw-prompt-scope-{Guid.NewGuid():N}"); |
| public async Task Authorization_evaluation_preserves_directory_for_duplicate_verb_candidates() | ||
| { | ||
| var root = Path.Combine(Path.GetTempPath(), $"netclaw-prompt-scope-{Guid.NewGuid():N}"); | ||
| var approvedDirectory = Path.Combine(root, "approved"); |
| { | ||
| var root = Path.Combine(Path.GetTempPath(), $"netclaw-prompt-scope-{Guid.NewGuid():N}"); | ||
| var approvedDirectory = Path.Combine(root, "approved"); | ||
| var unapprovedDirectory = Path.Combine(root, "unapproved"); |
| var tempFile = Path.GetTempFileName(); | ||
| try | ||
| { | ||
| var grantDir = Path.Combine(Path.GetTempPath(), "netclaw-approval", "repo"); |
| try | ||
| { | ||
| var grantDir = Path.Combine(Path.GetTempPath(), "netclaw-approval", "repo"); | ||
| var approvedDir = Path.Combine(grantDir, "src"); |
| { | ||
| var grantDir = Path.Combine(Path.GetTempPath(), "netclaw-approval", "repo"); | ||
| var approvedDir = Path.Combine(grantDir, "src"); | ||
| var unapprovedDir = Path.Combine(Path.GetTempPath(), "netclaw-approval", "external"); |
Concrete prompt behaviorThis change keeps the full command visible, but narrows the approvable candidate set to exact occurrences that still lack a grant. Existing session grantCommand: git status && git pushIf Same verb in two directoriesCommand: git -C /work/repo-a push && git -C /work/repo-b pushIf Pipeline with a partial grantCommand: git push | curl https://example.invalidIf Fail-closed behaviorThe executor validates the complete ordered candidate result before narrowing. If an approval-service result omits, swaps, or contradicts a candidate, Netclaw keeps the broad prompt and does not treat the command as previously approved. Adversarial reviewThe adversarial reviewer found three blockers during development:
All three were fixed. The final adversarial review returned PASS with no blockers. |
Summary
Security and compatibility
An adversarial review found and verified fixes for incomplete candidate accounting, missing end-to-end directory proof, and JSON constructor compatibility. The final review passed with no blockers.
Verification
Closes #972