Skip to content

Reduce approval prompts for causal Bash diagnostic chains - #1925

Merged
Aaronontheweb merged 2 commits into
devfrom
feature/bash-causal-approval-intent
Aug 13, 2026
Merged

Reduce approval prompts for causal Bash diagnostic chains#1925
Aaronontheweb merged 2 commits into
devfrom
feature/bash-causal-approval-intent

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Collaborator

Summary

This change lets Netclaw evaluate a bounded Bash diagnostic chain under its authored directory intent.

Netclaw consumes ShellSyntaxTree 0.3.4 working-directory effects. It does not parse command names or executable-specific options.

Policy boundary

  • Real execution facts remain unchanged.
  • Protected paths remain terminal deny rules.
  • Session and stored grants must cover the directory transition and its first action.
  • Reviewed-safe policy can cover later diagnostic consumers under the eligible intent.
  • Folder grants use only each prerequisite's real scope.
  • Headless calls receive no reviewed-safe authority.
  • Native PowerShell remains strict.
  • Symlink targets and all possible fallback directories fail closed.
  • POSIX /tmp aliases map through host-resolved path facts.

The policy never rewrites source, arguments, the working directory, or model history.

Motivating case

cd /tmp && gh api repos/example/project/actions/jobs/123456/logs \
  > slopwatch.log 2>&1; wc -c slopwatch.log; head -100 slopwatch.log

Stored authority covers cd and gh api. Reviewed-safe policy can then cover wc and head under exact /tmp intent.

Validation

  • Netclaw.Security.Tests: 911 passed
  • Netclaw.Actors.Tests: 3,260 passed; one expected Windows-only skip
  • Focused causal and platform-temp tests: passed
  • Strict OpenSpec validation: passed
  • Header verification: passed
  • Changed-file Slopwatch: passed
  • git diff --check: passed
  • Public ShellSyntaxTree 0.3.4 resolution: verified
  • Adversarial review: PASS with no warnings

Native platform CI remains the delivery gate.

Comment on lines +121 to +129
foreach (var root in _temporaryRoots)
{
if ((IsWithinRoot(normalized, root.Authored)
|| IsWithinRoot(normalized, root.Canonical))
&& IsSafeTemporaryPath(normalized, root))
{
return true;
}
}
Comment on lines +149 to +160
foreach (var command in analysis.Commands)
{
if (command.WorkingDirectoryEffect is
ShellWorkingDirectoryEffect.ChangesOnSuccess
{
Target: ShellValueDomain.Exact exact
}
&& TryGetTemporaryRoot(exact.Value, out temporaryRoot))
{
return true;
}
}
Comment on lines +321 to +329
foreach (var root in _temporaryRoots)
{
if (PathEquals(normalized, root.Authored)
|| PathEquals(normalized, root.Canonical))
{
temporaryRoot = root;
return true;
}
}
Comment on lines +276 to +300
foreach (var argument in occurrence.Arguments.Where(static argument =>
argument.Argument.IsPath))
{
IReadOnlyList<string> values = argument.Value switch
{
ShellValueDomain.Exact exact => [exact.Value],
ShellValueDomain.FiniteSet finite => finite.Values,
_ => []
};
if (values.Count == 0)
return false;

foreach (var value in values)
{
var resolved = ShellTokenizer.NormalizePathToken(
value,
intentDirectory,
ShellPathStyle.Posix);
if (string.IsNullOrWhiteSpace(resolved)
|| !IsSafePath(resolved, intentDirectory))
{
return false;
}
}
}
Comment on lines +288 to +299
foreach (var value in values)
{
var resolved = ShellTokenizer.NormalizePathToken(
value,
intentDirectory,
ShellPathStyle.Posix);
if (string.IsNullOrWhiteSpace(resolved)
|| !IsSafePath(resolved, intentDirectory))
{
return false;
}
}
Comment on lines +460 to +470
foreach (var value in values)
{
var path = ShellTokenizer.NormalizePathToken(
value,
workingDirectory,
pathStyle);
if (string.IsNullOrWhiteSpace(path))
return null;

resolved.Add(path);
}
Comment thread src/Netclaw.Actors.Tests/Tools/DispatchingToolExecutorTests.cs Fixed
Comment thread src/Netclaw.Actors.Tests/Tools/DispatchingToolExecutorTests.cs Fixed
Comment thread src/Netclaw.Actors.Tests/Tools/DispatchingToolExecutorTests.cs Fixed
Comment on lines +100 to +102
var testRoot = Path.Combine(
Path.GetTempPath(),
$"netclaw-causal-alias-{Guid.NewGuid():N}");
var testRoot = Path.Combine(
Path.GetTempPath(),
$"netclaw-causal-alias-{Guid.NewGuid():N}");
var canonicalTemp = Path.Combine(testRoot, "canonical-temp");
@Aaronontheweb Aaronontheweb added the shell Issues related to the shell tool, since it has the largest security perimeter. label Aug 13, 2026
@Aaronontheweb
Aaronontheweb merged commit 95097cd into dev Aug 13, 2026
39 checks passed
@Aaronontheweb
Aaronontheweb deleted the feature/bash-causal-approval-intent branch August 13, 2026 21:31
Aaronontheweb added a commit that referenced this pull request Aug 20, 2026
* Sync delta specs for the last two completed changes

Apply the redirect-shared-temp-to-session-scratch delta to session-cwd and
tool-approval-gates. The OpenSpec CLI applied both files.

Merge the surface-reminder-schedule-failures delta into netclaw-scheduling by
hand. PR #2024 already corrected that requirement against the merged code, so a
programmatic apply would undo those corrections. Keep the corrected text and add
the scheduling-failure content:

- An execution failure and a scheduling failure share one ConsecutiveFailures
  count.
- A successful reschedule alone does not reset the count.
- An unattended reschedule site emits ReminderScheduleFailed at Warning severity,
  and ReminderAutoDisabled at Critical severity on the threshold.
- The set_reminder create path and update path return the error to the caller
  and emit no alert.

Drop three stale delta claims. The merged code disables a reminder. It does not
set a "paused" status and it does not write tasks.json. ReminderExecutionActor
has no ExecutionTimeoutSeconds constant, so the one-hour absolute limit stands.

* Archive the last two completed OpenSpec changes

Move each change to openspec/changes/archive/2026-08-19-<name>/. The code of
both changes is merged on dev.

- surface-reminder-schedule-failures: PR #1886.
- redirect-shared-temp-to-session-scratch: PRs #1890, #1925, #1926, #1945, and
  #1956.

Tick task 4.3 of redirect-shared-temp-to-session-scratch. The full pr_validation
suite ran green on Windows against current dev.

Leave the other boxes unticked. The maintainer accepts tasks 4.5 and 4.6 of
surface-reminder-schedule-failures as guaranteed by construction. The maintainer
accepts task 6.4 of that change and task 4.4 of
redirect-shared-temp-to-session-scratch as an eval-credentials gap.
@Aaronontheweb Aaronontheweb mentioned this pull request Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

shell Issues related to the shell tool, since it has the largest security perimeter.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant