Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
79 changes: 71 additions & 8 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 @@ -1366,7 +1429,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
24 changes: 17 additions & 7 deletions Cargo.lock

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

2 changes: 0 additions & 2 deletions crates/agent-policy-tester/src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,6 @@ async fn assert_redirected_policy_rejected(
"ExpectedStoreToken": management["Management"]["StoreToken"],
"Operation": "Repair",
"ConflictHandling": "Reject",
"WarningsAcknowledged": false,
"Draft": full_policy(),
"ValidationReceipt": "invalid"
});
Expand Down Expand Up @@ -393,7 +392,6 @@ async fn replace_policy(
"ExpectedStoreToken": expected_store_token,
"Operation": operation,
"ConflictHandling": "Reject",
"WarningsAcknowledged": true,
"Draft": validation["CanonicalDraft"],
"ValidationReceipt": validation["ValidationReceipt"]
});
Expand Down
13 changes: 13 additions & 0 deletions crates/agent-sysevent-codes/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "agent-sysevent-codes"
version = "0.0.0"
edition = "2024"
authors = ["Devolutions Inc. <infos@devolutions.net>"]
license = "MIT OR Apache-2.0"
publish = false

[lints]
workspace = true

[dependencies]
sysevent.path = "../sysevent"
123 changes: 123 additions & 0 deletions crates/agent-sysevent-codes/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//! Devolutions Agent-specific Windows Event Log event definitions.

use std::path::Path;

use sysevent::{Entry, Severity};

pub const POLICY_WRITE_ATTEMPTED: u32 = 8000;
pub const POLICY_WRITE_DENIED: u32 = 8001;
pub const POLICY_CREATE_FAILED: u32 = 8002;
pub const POLICY_CREATE_SUCCEEDED: u32 = 8003;
pub const POLICY_CHANGE_FAILED: u32 = 8004;
pub const POLICY_CHANGE_SUCCEEDED: u32 = 8005;
pub const POLICY_EXTERNAL_CHANGE_APPLIED: u32 = 8010;
pub const POLICY_EXTERNAL_CHANGE_REJECTED: u32 = 8011;

pub fn policy_write_attempted(
actor_sid: impl ToString,
actor_exe: impl ToString,
intent: impl ToString,
path: &Path,
) -> Entry {
Entry::new("Policy management write attempted")
.event_code(POLICY_WRITE_ATTEMPTED)
.severity(Severity::Info)
.field("actor_sid", actor_sid)
.field("actor_exe", actor_exe)
.field("intent", intent)
.field("path", path.display())
}

pub fn policy_write_denied(
actor_sid: impl ToString,
actor_exe: impl ToString,
intent: impl ToString,
path: &Path,
reason: impl ToString,
) -> Entry {
Entry::new("Policy management write denied")
.event_code(POLICY_WRITE_DENIED)
.severity(Severity::Warning)
.field("actor_sid", actor_sid)
.field("actor_exe", actor_exe)
.field("intent", intent)
.field("path", path.display())
.field("reason", reason)
}

#[expect(
clippy::too_many_arguments,
reason = "the shared builder keeps the Create and change failure events field-compatible"
)]
pub fn policy_write_failed(
event_code: u32,
message: &'static str,
actor_sid: impl ToString,
actor_exe: impl ToString,
intent: impl ToString,
path: impl AsRef<Path>,
operation: impl ToString,
outcome: impl ToString,
reason: impl ToString,
) -> Entry {
Entry::new(message)
.event_code(event_code)
.severity(Severity::Error)
.field("actor_sid", actor_sid)
.field("actor_exe", actor_exe)
.field("intent", intent)
.field("path", path.as_ref().display())
.field("operation", operation)
.field("outcome", outcome)
.field("reason", reason)
}

#[expect(
clippy::too_many_arguments,
reason = "the audit event records both policy identities and the operation outcome"
)]
pub fn policy_write_succeeded(
event_code: u32,
message: &'static str,
actor_sid: impl ToString,
actor_exe: impl ToString,
path: impl AsRef<Path>,
old_id: impl ToString,
old_revision: impl ToString,
new_id: impl ToString,
new_revision: u32,
intent: impl ToString,
operation: impl ToString,
outcome: impl ToString,
) -> Entry {
Entry::new(message)
.event_code(event_code)
.severity(Severity::Info)
.field("actor_sid", actor_sid)
.field("actor_exe", actor_exe)
.field("path", path.as_ref().display())
.field("old_id", old_id)
.field("old_revision", old_revision)
.field("new_id", new_id)
.field("new_revision", new_revision)
.field("intent", intent)
.field("operation", operation)
.field("outcome", outcome)
}

pub fn policy_external_change_applied(path: impl AsRef<Path>, new_id: impl ToString, new_revision: u32) -> Entry {
Entry::new("External policy change applied")
.event_code(POLICY_EXTERNAL_CHANGE_APPLIED)
.severity(Severity::Notice)
.field("path", path.as_ref().display())
.field("new_id", new_id)
.field("new_revision", new_revision)
}

pub fn policy_external_change_rejected(path: impl AsRef<Path>, reason: impl ToString) -> Entry {
Entry::new("External policy change rejected")
.event_code(POLICY_EXTERNAL_CHANGE_REJECTED)
.severity(Severity::Warning)
.field("path", path.as_ref().display())
.field("reason", reason)
}
Loading
Loading