diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-08-13 22:48:24 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-08-13 22:48:24 +0900 |
| commit | 9337ac3e5edd42bb17f5e2ade6c2de02c7ef576d (patch) | |
| tree | 9a48fefc88cc046f4ce1e2bc34fa0a47351e4f83 /tests/Agent.Windows.Tests | |
| parent | 36ae1a4cba791ec633a81b38b1d8345af8487276 (diff) | |
feat!: isolate privileged sandbox network operations per task
Run agent-mcp with an explicit asInvoker manifest and move WFP and loopback mutations into a fixed requireAdministrator helper under the release admin directory.
Add the Agent.Admin client and host projects with task-scoped runas launch, a logon-SID and Administrators-only local named pipe, remote-client rejection, mutual PID validation, strict versioned JSON framing, fixed network-only operations, and bounded messages.
Delay ACL and network Task Resource application until the first process_run. Verify executable identity, managed entry points, DNS snapshots, and normal-token WRITE_DAC access before elevation; reuse the helper only within the Task and keep elevation failures terminal without policy replanning.
Keep LPAC creation, executable approval, Job confinement, and ACL leases in the normal process. Make startup platform checks read-only, create the fixed Application Profile during apply, preserve dynamic WFP lifetime in the helper, and route persistent loopback recovery through the same elevated boundary.
Update recovery journaling, localized elevation and IPC errors, audit events, release publishing, manifests, README guidance, Specifications, Design, implementation records, and requirement traceability for the on-demand elevation model.
Add administrative-boundary, file-only no-elevation, elevation-terminal, lazy-resource, crash-recovery, manifest, IPC schema, and operational verification coverage. Verified Release build with zero warnings, Core 105/105, Planner 10/10, administrative boundary 4/4, elevated Windows suite 79/79, and published stdio/HTTP MCP E2E.
Diffstat (limited to 'tests/Agent.Windows.Tests')
6 files changed, 223 insertions, 23 deletions
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); |
