Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
5928959
fix(agent): harden policy storage
CBenoit Sep 8, 2026
e3c8862
fix(agent): preserve policy path diagnostics
CBenoit Sep 8, 2026
e5ba9f6
fix(agent): address policy storage review
CBenoit Sep 8, 2026
212a50d
fix(agent): preserve configured policy identity
CBenoit Sep 8, 2026
a4258ad
fix(agent): enforce policy read barrier
CBenoit Sep 8, 2026
2c24e14
fix(agent): resolve policy storage review
CBenoit Sep 8, 2026
31b3b11
fix(agent): close policy storage review gaps
CBenoit Sep 8, 2026
0a7755a
fix(agent): bind policy recovery identity
CBenoit Sep 8, 2026
0234ff1
fix(agent): complete policy crash recovery
CBenoit Sep 8, 2026
a00c1b8
fix(agent): stabilize policy security digests
CBenoit Sep 8, 2026
2f76fb7
fix(agent): align policy recovery validation
CBenoit Sep 8, 2026
4290a3d
fix(agent): bind policy ancestor identity
CBenoit Sep 8, 2026
8b5c78b
fix(agent): verify no-replace rename semantics
CBenoit Sep 8, 2026
6c186df
fix(agent): verify probe entries by identity
CBenoit Sep 8, 2026
839475f
fix(agent): reject unsafe policy leaf states
CBenoit Sep 8, 2026
1c85311
fix(agent): watch canonical policy paths
CBenoit Sep 8, 2026
29245cf
fix(agent): remove stale watcher state
CBenoit Sep 8, 2026
8db997f
fix(agent): persist managed policy authority
CBenoit Sep 8, 2026
aaa4849
docs(agent): clarify canonical path use
CBenoit Sep 8, 2026
7cfa397
fix(agent): atomically mark managed authority
CBenoit Sep 8, 2026
d70cfba
fix(agent): preserve policy storage compatibility
CBenoit Sep 15, 2026
88c8cdb
test(agent): clarify storage fixture failures
CBenoit Sep 15, 2026
ddd4621
test(agent): release recovery fixtures
CBenoit Sep 16, 2026
5dddf6b
fix(agent): preserve trusted policy owner
CBenoit Sep 16, 2026
0239955
refactor(agent): keep canonical policy storage
CBenoit Sep 16, 2026
c343962
fix(agent): adopt final policy contract
CBenoit Sep 17, 2026
55d54fb
feat(agent): add policy audit events
CBenoit Sep 8, 2026
a339531
build(dgw,agent): embed policy event catalogs
CBenoit Sep 8, 2026
de89049
test(dgw,agent): enforce event catalog parity
CBenoit Sep 8, 2026
5ba83b2
fix(dgw,agent): harden policy audit validation
CBenoit Sep 9, 2026
88a4855
fix(agent): audit legacy policy rejection
CBenoit Sep 15, 2026
d03f8ef
fix(dgw,agent): compile localized event messages
CBenoit Sep 15, 2026
8eedb43
fix(dgw,agent,agent-installer): retain canonical audits
CBenoit Sep 17, 2026
ef41b35
test(agent): cover policy management end to end
CBenoit Sep 8, 2026
187c0df
ci(agent): run policy E2E as both identities
CBenoit Sep 8, 2026
92ea70f
test(agent): separate policy client identity
CBenoit Sep 9, 2026
43d13a7
ci(agent): handle detached policy tester launch
CBenoit Sep 9, 2026
91bbd8f
test(agent): use medium-integrity policy client
CBenoit Sep 9, 2026
bf99c01
ci(agent): stop policy server after launch failures
CBenoit Sep 9, 2026
eca6299
test(agent): exercise revised policy lifecycle
CBenoit Sep 15, 2026
cd4a2dc
fix(agent): restore NuGet test imports for SYSTEM
CBenoit Sep 15, 2026
b05aeb4
fix(agent): run installer tests as LocalSystem
CBenoit Sep 15, 2026
7fbf4cd
fix(agent): authenticate installer E2E client
CBenoit Sep 15, 2026
9f16052
test(agent): retain canonical policy E2E
CBenoit Sep 17, 2026
486c4ea
test(agent): cover final policy contract
CBenoit Sep 17, 2026
ff4031b
test(agent): cover policy review gaps
CBenoit Sep 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 94 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,6 @@ jobs:
$VSINSTALLDIR = $(vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Llvm.Clang -property installationPath)
Write-Output "LIBCLANG_PATH=$VSINSTALLDIR\VC\Tools\Llvm\x64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

# Install Visual Studio Developer PowerShell Module for cmdlets such as Enter-VsDevShell
Install-Module VsDevShell -Force
shell: pwsh

- name: Configure Windows (arm) runner
Expand Down Expand Up @@ -696,9 +694,6 @@ jobs:
# NASM is required by aws-lc-rs (used as rustls crypto backend)
choco install nasm

# Install Visual Studio Developer PowerShell Module for cmdlets such as Enter-VsDevShell
Install-Module VsDevShell -Force

# We need to add the NASM binary folder to the PATH manually.
Write-Output "$Env:ProgramFiles\NASM" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
shell: pwsh
Expand All @@ -707,9 +702,31 @@ jobs:
id: find_mc
if: ${{ matrix.os == 'windows' }}
run: |
Enter-VsDevShell
$path = (Get-Command -Type Application mc).Source | Split-Path -Parent
$sdkRoots = @(
$Env:WindowsSdkDir
(Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots" -Name KitsRoot10 -ErrorAction SilentlyContinue)
"${Env:ProgramFiles(x86)}\Windows Kits\10"
) | Where-Object { $_ } | Select-Object -Unique
$candidates = @()
if ($Env:WindowsSdkVerBinPath) {
$candidates += Join-Path $Env:WindowsSdkVerBinPath "mc.exe"
$candidates += Join-Path $Env:WindowsSdkVerBinPath "x64\mc.exe"
}
foreach ($root in $sdkRoots) {
$bin = Join-Path $root "bin"
$candidates += Join-Path $bin "x64\mc.exe"
$candidates += Get-ChildItem -LiteralPath $bin -Directory -ErrorAction SilentlyContinue |
Where-Object Name -Match '^\d+\.\d+\.\d+\.\d+$' |
Sort-Object { [version]$_.Name } -Descending |
ForEach-Object { Join-Path $_.FullName "x64\mc.exe" }
}
$mc = $candidates | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | Select-Object -First 1
if (-Not $mc) {
throw "mc.exe was not found in the installed Windows SDK"
}
$path = Split-Path -Parent $mc
Write-Output "windows_sdk_ver_bin_path=$path" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
Write-Output $path | Out-File -FilePath $env:GITHUB_PATH -Append -Encoding utf8
shell: pwsh

- name: Build
Expand Down Expand Up @@ -975,6 +992,37 @@ jobs:
if: ${{ matrix.os == 'windows' }}
uses: microsoft/setup-msbuild@v3

- name: Find mc.exe
id: find_mc
if: ${{ matrix.os == 'windows' }}
run: |
$sdkRoots = @(
$Env:WindowsSdkDir
(Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots" -Name KitsRoot10 -ErrorAction SilentlyContinue)
"${Env:ProgramFiles(x86)}\Windows Kits\10"
) | Where-Object { $_ } | Select-Object -Unique
$candidates = @()
if ($Env:WindowsSdkVerBinPath) {
$candidates += Join-Path $Env:WindowsSdkVerBinPath "mc.exe"
$candidates += Join-Path $Env:WindowsSdkVerBinPath "x64\mc.exe"
}
foreach ($root in $sdkRoots) {
$bin = Join-Path $root "bin"
$candidates += Join-Path $bin "x64\mc.exe"
$candidates += Get-ChildItem -LiteralPath $bin -Directory -ErrorAction SilentlyContinue |
Where-Object Name -Match '^\d+\.\d+\.\d+\.\d+$' |
Sort-Object { [version]$_.Name } -Descending |
ForEach-Object { Join-Path $_.FullName "x64\mc.exe" }
}
$mc = $candidates | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | Select-Object -First 1
if (-Not $mc) {
throw "mc.exe was not found in the installed Windows SDK"
}
$path = Split-Path -Parent $mc
Write-Output "windows_sdk_ver_bin_path=$path" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
Write-Output $path | Out-File -FilePath $env:GITHUB_PATH -Append -Encoding utf8
shell: pwsh

- name: Build
run: |
if ($Env:RUNNER_OS -eq "Windows") {
Expand All @@ -985,6 +1033,7 @@ jobs:
$Env:DAGENT_TUN2SOCKS_EXE = "${{ steps.tun2socks.outputs.tun2socks-executable-path }}"
$Env:DAGENT_WINTUN_DLL = "${{ steps.tun2socks.outputs.wintun-library-path }}"
$Env:DAGENT_MULTI_PWSH_EXECUTABLE = "${{ steps.multi-pwsh.outputs.executable-path }}"
$Env:WindowsSdkVerBinPath = '${{ steps.find_mc.outputs.windows_sdk_ver_bin_path }}'
}

if ($Env:RUNNER_OS -eq "Linux") {
Expand Down Expand Up @@ -1122,6 +1171,20 @@ jobs:
run: dotnet test utils/dotnet/GatewayUtils.sln
shell: pwsh

agent-installer-event-log-tests:
name: Agent installer Event Log lifecycle tests
runs-on: windows-2022
needs: [preflight]

steps:
- name: Checkout ${{ github.repository }}
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.ref }}

- name: Tests
run: dotnet test package/AgentWindowsManaged.Tests/DevolutionsAgent.Installer.Tests.csproj
shell: pwsh

winapi-sanitizer-tests:
name: Windows API sanitizer tests
Expand Down Expand Up @@ -1283,12 +1346,14 @@ jobs:
name: Agent policy end-to-end test
runs-on: windows-2022
needs: [preflight]
env:
AGENT_POLICY_TEST_SHA: ${{ inputs.ref || github.event.pull_request.head.sha || needs.preflight.outputs.ref }}

steps:
- name: Checkout ${{ github.repository }}
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.ref }}
ref: ${{ env.AGENT_POLICY_TEST_SHA }}

- name: Setup Rust cache
uses: ./.github/actions/setup-rust-cache
Expand All @@ -1311,8 +1376,13 @@ jobs:
Add-Content -Path $env:GITHUB_PATH -Value $toolsDir

- name: Build Agent policy test executables
id: build-policy-executables
shell: pwsh
run: |
$actualCommit = git rev-parse HEAD
if ($LASTEXITCODE -ne 0 -or $actualCommit -ne $env:AGENT_POLICY_TEST_SHA) {
throw "Agent policy tests must build the requested commit $env:AGENT_POLICY_TEST_SHA, got $actualCommit"
}
cargo build --locked -p devolutions-agent --features dev-skip-broker-signature
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
Expand All @@ -1322,7 +1392,18 @@ jobs:
exit $LASTEXITCODE
}

- name: Run Agent policy tester as standard user
shell: pwsh
run: |
./crates/agent-policy-tester/run-unelevated.ps1
$exitCode = $LASTEXITCODE
Get-Content -Path ./crates/agent-policy-tester/agent-policy-tester-unelevated.out
if ($exitCode -ne 0) {
exit $exitCode
}

- name: Run Agent policy tester as LocalSystem
if: ${{ !cancelled() && steps.build-policy-executables.outcome == 'success' }}
shell: pwsh
run: |
$scriptPath = Resolve-Path -Path "./crates/agent-policy-tester/run-as-system.ps1"
Expand All @@ -1333,6 +1414,10 @@ jobs:
exit $exitCode
}

- name: Run policy route authorization tests
shell: pwsh
run: cargo test --locked -p now-package-broker --features dev-skip-broker-signature

- name: Show sccache stats
if: ${{ needs.preflight.outputs.sccache == 'true' && !cancelled() }}
shell: pwsh
Expand Down Expand Up @@ -1366,7 +1451,7 @@ jobs:
success:
name: Success
if: ${{ always() }}
needs: [tests, agent-tunnel-e2e, agent-policy-e2e, lints, check-dependencies, jetsocat-lipo, devolutions-gateway-powershell, devolutions-gateway, devolutions-gateway-merge, devolutions-pedm-desktop, devolutions-agent, devolutions-agent-merge, devolutions-pedm-client, dotnet-utils-tests, winapi-sanitizer-tests, winapi-miri, pedm-simulator, secure-memory-verifier]
needs: [tests, agent-tunnel-e2e, agent-policy-e2e, lints, check-dependencies, jetsocat-lipo, devolutions-gateway-powershell, devolutions-gateway, devolutions-gateway-merge, devolutions-pedm-desktop, devolutions-agent, devolutions-agent-merge, devolutions-pedm-client, dotnet-utils-tests, agent-installer-event-log-tests, winapi-sanitizer-tests, winapi-miri, pedm-simulator, secure-memory-verifier]
runs-on: ubuntu-latest

steps:
Expand Down
19 changes: 13 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/agent-policy-tester/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ fastrand = "2"
serde_json = "1"
tempfile = "3"
tokio = { version = "1", features = ["io-util", "macros", "net", "process", "rt-multi-thread", "time"] }
win-api-wrappers = { path = "../win-api-wrappers" }
windows = { version = "0.61", features = ["Win32_Security", "Win32_System_Threading"] }

[lints]
workspace = true
13 changes: 10 additions & 3 deletions crates/agent-policy-tester/run-as-system.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ $workspacePath = (Resolve-Path (Join-Path $PSScriptRoot "../..")).Path
$testerPath = Join-Path $workspacePath "target/debug/agent-policy-tester.exe"
$agentPath = Join-Path $workspacePath "target/debug/devolutions-agent.exe"
$outputPath = Join-Path $PSScriptRoot "agent-policy-tester.out"
$stagingPath = Join-Path $env:ProgramData "dgw-agent-policy-tester-$([guid]::NewGuid().ToString('N'))"
$stagingPath = Join-Path ([Environment]::GetFolderPath('CommonApplicationData')) "dgw-agent-policy-tester-$([guid]::NewGuid().ToString('N'))"
$stagedTesterPath = Join-Path $stagingPath "agent-policy-tester.exe"
$exitCode = 1

try {
Set-Content -LiteralPath $outputPath -Value ""
if (-not [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem) {
throw "This runner requires LocalSystem"
}
if ([System.IO.DriveInfo]::new([System.IO.Path]::GetPathRoot($workspacePath)).DriveType -ne 'Fixed') {
throw "Use a local fixed-volume workspace path visible to LocalSystem, not a mapped drive"
}
Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
Expand Down Expand Up @@ -61,7 +68,6 @@ public static class AgentPolicyTesterNativeDirectory
if (Get-ChildItem -LiteralPath $stagingPath -Force) {
throw "The atomically protected staged tester directory was not empty"
}

Copy-Item -LiteralPath $testerPath -Destination $stagedTesterPath
& icacls.exe $stagedTesterPath /setowner '*S-1-5-18' 2>&1 | Out-File $outputPath -Append
if ($LASTEXITCODE -ne 0) {
Expand All @@ -76,7 +82,7 @@ public static class AgentPolicyTesterNativeDirectory
"Staged policy tester at $stagedTesterPath" | Out-File $outputPath -Append
Get-Acl -LiteralPath $stagingPath | Format-List Owner, Sddl | Out-File $outputPath -Append
Get-Acl -LiteralPath $stagedTesterPath | Format-List Owner, Sddl | Out-File $outputPath -Append
& $stagedTesterPath $agentPath 2>&1 | Out-File $outputPath -Append
& $stagedTesterPath $agentPath elevated 2>&1 | Out-File $outputPath -Append
$exitCode = $LASTEXITCODE
} catch {
$_ | Out-File $outputPath -Append
Expand All @@ -88,6 +94,7 @@ public static class AgentPolicyTesterNativeDirectory
} catch {
if ($attempt -eq 19) {
"Failed to remove $stagingPath after 20 attempts: $_" | Out-File $outputPath -Append
$exitCode = 1
} else {
Start-Sleep -Milliseconds 250
}
Expand Down
Loading
Loading