diff options
Diffstat (limited to 'tests')
7 files changed, 258 insertions, 23 deletions
diff --git a/tests/Agent.Core.Tests/PromptAndRuntimeTests.cs b/tests/Agent.Core.Tests/PromptAndRuntimeTests.cs index b7f27e7..04a9714 100644 --- a/tests/Agent.Core.Tests/PromptAndRuntimeTests.cs +++ b/tests/Agent.Core.Tests/PromptAndRuntimeTests.cs @@ -205,6 +205,27 @@ public sealed class PromptAndRuntimeTests } [Fact] + public async Task Elevation_failure_is_terminal_for_the_task_without_policy_replanning() + { + TaskRegistry registry = new(); + var backend = new PlatformFailingBackend(); + var dispatcher = new InternalToolDispatcher( + new DenyByDefaultPolicy(new HashSet<string>(["process_run"], StringComparer.Ordinal)), backend); + var runtime = new AgentRuntime(registry, new FailingThenFinalOllamaClient(), + new AgentRuntimeSettings("", "en", [], "sandbox", MaxIterations: 10, SameFailureLimit: 2), dispatcher); + TaskSnapshot task = registry.Enqueue("run build", null, null); + registry.Transition(task.TaskId, AgentTaskState.Planning); + + await runtime.ExecuteAsync(task.TaskId, TestContext.Current.CancellationToken); + + Assert.True(registry.TryGet(task.TaskId, null, out TaskSnapshot? failed)); + Assert.Equal(AgentTaskState.Failed, failed!.State); + Assert.Equal(0, failed.Replans); + Assert.Equal("sandbox.elevation_cancelled", failed.LastErrorCode); + Assert.Equal(1, backend.CallCount); + } + + [Fact] public async Task Runtime_does_not_retry_a_sandbox_policy_denial() { TaskRegistry registry = new(); @@ -577,6 +598,20 @@ public sealed class PromptAndRuntimeTests public Task EndTaskAsync(Guid taskId, bool success, CancellationToken cancellationToken) => Task.CompletedTask; } + private sealed class PlatformFailingBackend : IInternalToolBackend + { + public int CallCount { get; private set; } + public Task BeginTaskAsync(Guid taskId, Guid sessionId, CancellationToken cancellationToken) => Task.CompletedTask; + public Task<ToolExecutionResult> ExecuteAsync(Guid taskId, string toolName, JsonElement arguments, CancellationToken cancellationToken) + { + CallCount++; + return Task.FromResult(new ToolExecutionResult(false, "The Windows elevation request was cancelled.", false, + "process_run:sandbox.elevation_cancelled", RetryAllowed: false, + ErrorCode: "sandbox.elevation_cancelled", ErrorCategory: "platform")); + } + public Task EndTaskAsync(Guid taskId, bool success, CancellationToken cancellationToken) => Task.CompletedTask; + } + private sealed class FailingThenFinalOllamaClient : IOllamaClient { private int _calls; diff --git a/tests/Agent.Windows.Tests/AdministrativeBoundaryTests.cs b/tests/Agent.Windows.Tests/AdministrativeBoundaryTests.cs new file mode 100644 index 0000000..b218072 --- /dev/null +++ b/tests/Agent.Windows.Tests/AdministrativeBoundaryTests.cs @@ -0,0 +1,87 @@ +using System.Buffers.Binary; +using System.Text; +using System.Text.Json; +using Agent.Admin.Client; + +namespace Agent.Windows.Tests; + +public sealed class AdministrativeBoundaryTests +{ + [Fact] + public async Task Administrative_protocol_round_trips_only_the_fixed_network_request_shape() + { + var request = new AdminRequest(AdminProtocol.Version, "apply-network", Guid.NewGuid(), "S-1-15-2-1", "local", + [new("127.0.0.1", 11434)], false); + using var stream = new MemoryStream(); + await AdminProtocol.WriteAsync(stream, request, TestContext.Current.CancellationToken); + stream.Position = 0; + AdminRequest actual = await AdminProtocol.ReadAsync<AdminRequest>(stream, TestContext.Current.CancellationToken); + Assert.Equal(request.Version, actual.Version); + Assert.Equal(request.Operation, actual.Operation); + Assert.Equal(request.TaskId, actual.TaskId); + Assert.Equal(request.ApplicationSid, actual.ApplicationSid); + Assert.Equal(request.NetworkAccess, actual.NetworkAccess); + Assert.Equal(request.OriginallyLoopbackExempt, actual.OriginallyLoopbackExempt); + Assert.Equal(request.Endpoints, actual.Endpoints); + string json = Encoding.UTF8.GetString(stream.ToArray()); + Assert.DoesNotContain("executable", json, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("commandLine", json, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("securityDescriptor", json, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("layer", json, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("action", json, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public async Task Administrative_protocol_rejects_oversized_messages_before_allocation() + { + byte[] header = new byte[4]; + BinaryPrimitives.WriteInt32LittleEndian(header, AdminProtocol.MaxMessageBytes + 1); + using var stream = new MemoryStream(header); + await Assert.ThrowsAsync<InvalidDataException>(() => AdminProtocol.ReadAsync<AdminRequest>(stream, + TestContext.Current.CancellationToken)); + } + + [Fact] + public async Task Administrative_protocol_rejects_fields_outside_the_fixed_schema() + { + byte[] payload = Encoding.UTF8.GetBytes("""{"version":1,"operation":"hello","taskId":"00000000-0000-0000-0000-000000000000","command":"cmd.exe"}"""); + byte[] framed = new byte[payload.Length + 4]; + BinaryPrimitives.WriteInt32LittleEndian(framed, payload.Length); + payload.CopyTo(framed.AsSpan(4)); + using var stream = new MemoryStream(framed); + + await Assert.ThrowsAsync<JsonException>(() => AdminProtocol.ReadAsync<AdminRequest>(stream, + TestContext.Current.CancellationToken)); + } + + [Fact] + public void Manifests_and_native_call_ownership_match_the_process_boundary() + { + string root = RepositoryRoot(); + string mainManifest = File.ReadAllText(Path.Combine(root, "src", "Agent.App", "app.manifest")); + string helperManifest = File.ReadAllText(Path.Combine(root, "src", "Agent.Admin", "Agent.Admin.Host", "app.manifest")); + Assert.Contains("level=\"asInvoker\"", mainManifest, StringComparison.Ordinal); + Assert.Contains("level=\"requireAdministrator\"", helperManifest, StringComparison.Ordinal); + Assert.Contains("uiAccess=\"false\"", helperManifest, StringComparison.Ordinal); + string normalNative = File.ReadAllText(Path.Combine(root, "src", "Agent.Windows", "NativeMethods.txt")); + Assert.DoesNotContain("FwpmTransactionBegin0", normalNative, StringComparison.Ordinal); + Assert.DoesNotContain("FwpmFilterAdd0", normalNative, StringComparison.Ordinal); + Assert.DoesNotContain("NetworkIsolationSetAppContainerConfig", normalNative, StringComparison.Ordinal); + string helperNative = File.ReadAllText(Path.Combine(root, "src", "Agent.Admin", "Agent.Admin.Host", "NativeMethods.txt")); + Assert.Contains("FwpmTransactionBegin0", helperNative, StringComparison.Ordinal); + Assert.Contains("NetworkIsolationSetAppContainerConfig", helperNative, StringComparison.Ordinal); + string client = File.ReadAllText(Path.Combine(root, "src", "Agent.Admin", "Agent.Admin.Client", "ElevatedNetworkSession.cs")); + Assert.Contains("PipeRejectRemoteClients", client, StringComparison.Ordinal); + } + + private static string RepositoryRoot() + { + DirectoryInfo? current = new(AppContext.BaseDirectory); + while (current is not null) + { + if (File.Exists(Path.Combine(current.FullName, "AgentSandboxMcp.slnx"))) return current.FullName; + current = current.Parent; + } + throw new DirectoryNotFoundException("Repository root was not found."); + } +} diff --git a/tests/Agent.Windows.Tests/Agent.Windows.Tests.csproj b/tests/Agent.Windows.Tests/Agent.Windows.Tests.csproj index 7888f53..ec4f87f 100644 --- a/tests/Agent.Windows.Tests/Agent.Windows.Tests.csproj +++ b/tests/Agent.Windows.Tests/Agent.Windows.Tests.csproj @@ -6,6 +6,7 @@ <TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport> </PropertyGroup> <ItemGroup> + <ProjectReference Include="..\..\src\Agent.Admin\Agent.Admin.Host\Agent.Admin.Host.csproj" /> <ProjectReference Include="..\..\src\Agent.Windows\Agent.Windows.csproj" /> <ProjectReference Include="..\..\src\Agent.App\Agent.App.csproj" /> </ItemGroup> diff --git a/tests/Agent.Windows.Tests/CrashScenarioBootstrap.cs b/tests/Agent.Windows.Tests/CrashScenarioBootstrap.cs index 6686833..d3224f4 100644 --- a/tests/Agent.Windows.Tests/CrashScenarioBootstrap.cs +++ b/tests/Agent.Windows.Tests/CrashScenarioBootstrap.cs @@ -80,7 +80,9 @@ internal static class CrashScenarioBootstrap edit.Rollback(); break; case "wfp": - _ = TaskNetworkPolicy.Apply(journal, AppContainerProfile.EnsureFixed().Sid, [], new MemorySecurityAuditSink()); + _ = TaskNetworkPolicy.ApplyAsync(new DirectElevatedNetworkSession(), journal, + AppContainerProfile.EnsureFixed().Sid, "none", [], new MemorySecurityAuditSink(), null, + CancellationToken.None).GetAwaiter().GetResult(); break; default: throw new InvalidOperationException($"Unknown crash scenario '{scenario}'."); diff --git a/tests/Agent.Windows.Tests/DirectElevatedNetworkSession.cs b/tests/Agent.Windows.Tests/DirectElevatedNetworkSession.cs new file mode 100644 index 0000000..b194ed1 --- /dev/null +++ b/tests/Agent.Windows.Tests/DirectElevatedNetworkSession.cs @@ -0,0 +1,75 @@ +using System.Net; +using System.Security.Principal; +using Agent.Admin.Client; +using Agent.Admin.Host; + +namespace Agent.Windows.Tests; + +internal sealed class DirectElevatedNetworkSession : IElevatedNetworkSession +{ + private WfpDynamicSession? _wfp; + private SecurityIdentifier? _sid; + private bool _loopbackAdded; + + public Task<bool> InspectLoopbackAsync(string applicationSid, CancellationToken cancellationToken) => + Task.FromResult(LoopbackExemption.Contains(new SecurityIdentifier(applicationSid))); + + public Task ApplyAsync(string applicationSid, string networkAccess, IReadOnlyList<AdminNetworkEndpoint> endpoints, + bool originallyLoopbackExempt, CancellationToken cancellationToken) + { + _sid = new(applicationSid); + NetworkEndpoint[] values = endpoints.Select(static item => new NetworkEndpoint(IPAddress.Parse(item.Address), (ushort)item.Port)).ToArray(); + _wfp = WfpDynamicSession.Open(); + _wfp.ApplyDefaultBlock(_sid, values); + if (values.Any(static item => IPAddress.IsLoopback(item.Address)) && !originallyLoopbackExempt) + _loopbackAdded = LoopbackExemption.Ensure(_sid); + return Task.CompletedTask; + } + + public Task RecoverLoopbackAsync(string applicationSid, bool originallyLoopbackExempt, CancellationToken cancellationToken) + { + var sid = new SecurityIdentifier(applicationSid); + if (originallyLoopbackExempt) _ = LoopbackExemption.Ensure(sid); else LoopbackExemption.Remove(sid); + return Task.CompletedTask; + } + + public Task CleanupAsync(CancellationToken cancellationToken) + { + if (_loopbackAdded && _sid is not null) LoopbackExemption.Remove(_sid); + _loopbackAdded = false; + if (_wfp is not null) { _wfp.RemovePolicy(); _wfp.Dispose(); _wfp = null; } + return Task.CompletedTask; + } + + public async ValueTask DisposeAsync() => await CleanupAsync(CancellationToken.None).ConfigureAwait(false); +} + +internal sealed class DirectElevatedNetworkSessionFactory : IElevatedNetworkSessionFactory +{ + public int Starts { get; private set; } + public Task<IElevatedNetworkSession> StartAsync(Guid taskId, CancellationToken cancellationToken) + { + Starts++; + return Task.FromResult<IElevatedNetworkSession>(new DirectElevatedNetworkSession()); + } +} + +internal sealed class NoOpElevatedNetworkSessionFactory : IElevatedNetworkSessionFactory +{ + public int Starts { get; private set; } + public Task<IElevatedNetworkSession> StartAsync(Guid taskId, CancellationToken cancellationToken) + { + Starts++; + return Task.FromResult<IElevatedNetworkSession>(new NoOpElevatedNetworkSession()); + } + + private sealed class NoOpElevatedNetworkSession : IElevatedNetworkSession + { + public Task<bool> InspectLoopbackAsync(string applicationSid, CancellationToken cancellationToken) => Task.FromResult(false); + public Task ApplyAsync(string applicationSid, string networkAccess, IReadOnlyList<AdminNetworkEndpoint> endpoints, + bool originallyLoopbackExempt, CancellationToken cancellationToken) => Task.CompletedTask; + public Task RecoverLoopbackAsync(string applicationSid, bool originallyLoopbackExempt, CancellationToken cancellationToken) => Task.CompletedTask; + public Task CleanupAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public ValueTask DisposeAsync() => ValueTask.CompletedTask; + } +} diff --git a/tests/Agent.Windows.Tests/ReadmeOperationalTests.cs b/tests/Agent.Windows.Tests/ReadmeOperationalTests.cs index fd70f06..5240feb 100644 --- a/tests/Agent.Windows.Tests/ReadmeOperationalTests.cs +++ b/tests/Agent.Windows.Tests/ReadmeOperationalTests.cs @@ -381,11 +381,12 @@ public sealed class ReadmeOperationalTests string journalRoot = Path.Combine(Path.GetTempPath(), "agent-mcp-readme-network", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(journalRoot); TaskResourceJournal journal = TaskResourceJournal.Create(journalRoot, scope.TaskId); - return new(journal, TaskNetworkPolicy.Apply(journal, scope.Profile.Sid, endpoints, scope.Audit)); + return new(journal, TaskNetworkPolicy.ApplyAsync(new DirectElevatedNetworkSession(), journal, scope.Profile.Sid, + endpoints.Count == 0 ? "none" : "local", endpoints, scope.Audit, null, CancellationToken.None).GetAwaiter().GetResult()); } public void Dispose() { - _policy.Dispose(); + _policy.DisposeAsync().AsTask().GetAwaiter().GetResult(); _journal.CompleteAndDelete(); string? root = Path.GetDirectoryName(_journal.Path); if (root is not null && Directory.Exists(root)) Directory.Delete(root, true); diff --git a/tests/Agent.Windows.Tests/SecurityPolicyTests.cs b/tests/Agent.Windows.Tests/SecurityPolicyTests.cs index 6dbc9ab..5b10417 100644 --- a/tests/Agent.Windows.Tests/SecurityPolicyTests.cs +++ b/tests/Agent.Windows.Tests/SecurityPolicyTests.cs @@ -11,6 +11,8 @@ using Agent.Core.Tools; using System.Text.Json; using Agent.App.Sandbox; using Agent.App.Configuration; +using LoopbackExemption = Agent.Admin.Host.LoopbackExemption; +using WfpDynamicSession = Agent.Admin.Host.WfpDynamicSession; namespace Agent.Windows.Tests; @@ -793,7 +795,7 @@ public sealed class SecurityPolicyTests try { - RecoveryResult recovered = new RecoveryManager(journals, audit).RecoverAll(); + RecoveryResult recovered = new RecoveryManager(journals, audit, new DirectElevatedNetworkSessionFactory()).RecoverAll(); Assert.True(recovered.IsClean); Assert.Equal(1, recovered.JournalsRecovered); @@ -957,7 +959,8 @@ public sealed class SecurityPolicyTests session.ProbeWriteTransaction(); IReadOnlyList<ulong> ids = session.ApplyDefaultBlock(profile.Sid, - [new NetworkEndpoint(IPAddress.Loopback, 11434), new NetworkEndpoint(IPAddress.IPv6Loopback, 11434)]); + [new Agent.Admin.Host.NetworkEndpoint(IPAddress.Loopback, 11434), + new Agent.Admin.Host.NetworkEndpoint(IPAddress.IPv6Loopback, 11434)]); Assert.Equal(4, ids.Count); Assert.All(ids, id => Assert.NotEqual(0UL, id)); @@ -965,7 +968,7 @@ public sealed class SecurityPolicyTests } [Fact] - public async Task Windows_backend_applies_file_effect_and_cleans_acl_wfp_temp_and_journal() + public async Task Windows_backend_file_only_effect_does_not_apply_acl_or_network_resources() { using TestDirectory directory = new(); string workspace = Path.Combine(directory.Path, "workspace"); @@ -978,7 +981,8 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write | FileCapability.Delete)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var elevated = new DirectElevatedNetworkSessionFactory(); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: elevated); Guid taskId = Guid.NewGuid(); Guid sessionId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, sessionId, TestContext.Current.CancellationToken); @@ -995,13 +999,13 @@ public sealed class SecurityPolicyTests Assert.Empty(Directory.EnumerateFiles(Path.Combine(directory.Path, "journals"))); string backups = Path.Combine(directory.Path, "backups"); Assert.True(!Directory.Exists(backups) || !Directory.EnumerateFileSystemEntries(backups).Any()); - Assert.Contains(audit.Events, item => item.Event == "network.rule.remove" && item.Data["residual_filters"] == "0"); + Assert.Equal(0, elevated.Starts); + Assert.DoesNotContain(audit.Events, item => item.Event is "network.rule.apply" or "network.rule.remove"); Assert.Contains(audit.Events, item => item.Event == "task.start" && item.SessionId == sessionId); Assert.Contains(audit.Events, item => item.Event == "tool.call" && item.SessionId == sessionId); Assert.Contains(audit.Events, item => item.Event == "file.write" && item.SessionId == sessionId); Assert.Contains(audit.Events, item => item.Event == "task.end" && item.SessionId == sessionId); - Assert.Single(audit.Events, item => item.Event == "acl.apply"); - Assert.Single(audit.Events, item => item.Event == "acl.restore"); + Assert.DoesNotContain(audit.Events, item => item.Event is "acl.apply" or "acl.restore"); } [Fact] @@ -1023,7 +1027,7 @@ public sealed class SecurityPolicyTests [new ApprovedEntryExecutable("cmd", cmd, EntryExecutablePolicy.ComputeSha256(cmd), true, null)], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000, BaselineCapabilities: ["registryRead", "lpacInstrumentation"]); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); @@ -1042,6 +1046,34 @@ public sealed class SecurityPolicyTests } [Fact] + public async Task File_only_task_does_not_start_the_elevated_helper() + { + using TestDirectory directory = new(); + string workspace = Path.Combine(directory.Path, "workspace"); + Directory.CreateDirectory(workspace); + string input = Path.Combine(workspace, "input.txt"); + File.WriteAllText(input, "read-only operation"); + var factory = new NoOpElevatedNetworkSessionFactory(); + var settings = new EffectiveSandboxPolicy( + [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write | FileCapability.Delete | FileCapability.Execute, "workspace")], + [], [], [workspace], new SandboxJobLimits(), "none", [], + Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), + 16 * 1024 * 1024, 1024 * 1024, 1000, 10000, + BaselineCapabilities: ["registryRead", "lpacInstrumentation"]); + var backend = new WindowsToolBackend(settings, new MemorySecurityAuditSink(), elevatedNetwork: factory); + Guid taskId = Guid.NewGuid(); + + await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); + using JsonDocument read = JsonDocument.Parse($$"""{"path":{{JsonSerializer.Serialize(input)}},"mode":"whole"}"""); + ToolExecutionResult result = await backend.ExecuteAsync(taskId, "file_read", read.RootElement, + TestContext.Current.CancellationToken); + await backend.EndTaskAsync(taskId, result.Success, TestContext.Current.CancellationToken); + + Assert.True(result.Success); + Assert.Equal(0, factory.Starts); + } + + [Fact] public async Task Dir_mkdir_creates_directory_within_approved_root_and_cleans_up() { using TestDirectory directory = new(); @@ -1054,7 +1086,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write | FileCapability.Delete)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument mkdir = JsonDocument.Parse($$"""{"path":{{JsonSerializer.Serialize(target)}},"operation":"mkdir"}"""); @@ -1085,7 +1117,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write | FileCapability.Delete)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument rmdir = JsonDocument.Parse($$"""{"path":{{JsonSerializer.Serialize(target)}},"operation":"rmdir"}"""); @@ -1113,7 +1145,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write | FileCapability.Delete)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument rmdir = JsonDocument.Parse($$"""{"path":{{JsonSerializer.Serialize(target)}},"operation":"rmdir"}"""); @@ -1140,7 +1172,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument list = JsonDocument.Parse($$"""{"path":{{JsonSerializer.Serialize(workspace)}},"operation":"list"}"""); @@ -1166,7 +1198,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); string badTarget = Path.Combine(outside.Path, "escaped"); @@ -1192,7 +1224,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument tail = JsonDocument.Parse($$"""{"root":{{JsonSerializer.Serialize(binaryFile)}},"mode":"tail","query":"","tail_lines":10}"""); @@ -1231,7 +1263,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument tail = JsonDocument.Parse($$"""{"root":{{JsonSerializer.Serialize(textFile)}},"mode":"tail","query":"","tail_lines":10}"""); @@ -1256,7 +1288,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write | FileCapability.Delete)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument rename = JsonDocument.Parse($$"""{"path":{{JsonSerializer.Serialize(source)}},"operation":"rename","new_path":{{JsonSerializer.Serialize(dest)}}}"""); @@ -1287,7 +1319,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument rename = JsonDocument.Parse($$"""{"path":{{JsonSerializer.Serialize(source)}},"operation":"rename","new_path":{{JsonSerializer.Serialize(dest)}}}"""); @@ -1317,7 +1349,7 @@ public sealed class SecurityPolicyTests [new FilePolicyEntry(workspace, FileCapability.Read | FileCapability.Write)], [], [], [], new SandboxJobLimits(), "none", [], Path.Combine(directory.Path, "journals"), Path.Combine(directory.Path, "backups"), 16 * 1024 * 1024, 1024 * 1024, 1000, 10000); - var backend = new WindowsToolBackend(settings, audit); + var backend = new WindowsToolBackend(settings, audit, elevatedNetwork: new DirectElevatedNetworkSessionFactory()); Guid taskId = Guid.NewGuid(); await backend.BeginTaskAsync(taskId, Guid.NewGuid(), TestContext.Current.CancellationToken); using JsonDocument rename = JsonDocument.Parse($$"""{"path":{{JsonSerializer.Serialize(source)}},"operation":"rename","new_path":{{JsonSerializer.Serialize(dest)}}}"""); @@ -1358,7 +1390,8 @@ public sealed class SecurityPolicyTests { Guid taskId = Guid.NewGuid(); TaskResourceJournal journal = TaskResourceJournal.Create(Path.Combine(directory.Path, "deny-journal"), taskId); - using (TaskNetworkPolicy.Apply(journal, profile.Sid, [], audit)) + await using (await TaskNetworkPolicy.ApplyAsync(new DirectElevatedNetworkSession(), journal, profile.Sid, + "none", [], audit, null, TestContext.Current.CancellationToken)) { RestrictedProcessResult denied = Curl(launcher, taskId, curl, deniedServer.Url, Environment.SystemDirectory); Assert.NotEqual(0u, denied.ExitCode); @@ -1383,7 +1416,8 @@ public sealed class SecurityPolicyTests [ new(allowedAddress, checked((ushort)allowedV4.Port)) ]; - using (TaskNetworkPolicy.Apply(allowJournal, profile.Sid, allowances, audit)) + await using (await TaskNetworkPolicy.ApplyAsync(new DirectElevatedNetworkSession(), allowJournal, profile.Sid, + "local", allowances, audit, null, TestContext.Current.CancellationToken)) { RestrictedProcessResult v4 = Curl(launcher, allowTaskId, curl, allowedV4.Url, Environment.SystemDirectory); RestrictedProcessResult wrongPort = Curl(launcher, allowTaskId, curl, deniedPort.Url, Environment.SystemDirectory); |
