Skip to content
Draft
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
54 changes: 32 additions & 22 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
pre_test: powershell -file .\bin\process_monitor.Tests\win-x64\Install-eBpfForWindows.ps1 1.4.0
test_command: .\ntosebpfext_unit.exe -d yes
build_artifact: Build-x64
environment: windows-2025
environment: '["windows-2025"]'
code_coverage: true
gather_dumps: true
capture_etw: true
Expand All @@ -92,42 +92,52 @@ jobs:
pre_test: powershell -file .\bin\process_monitor.Tests\win-x64\Install-eBpfForWindows.ps1 1.4.0 && powershell -file .\bin\process_monitor.Tests\win-x64\Setup-ProcessMonitorTests.ps1 -ArtifactsRoot .
test_command: dotnet test .\bin\process_monitor.Tests\win-x64\process_monitor.Tests.dll
build_artifact: Build-x64
environment: windows-2025
environment: '["windows-2025"]'
capture_etw: true

# Run the neteventebpfext driver tests in GitHub.
# Run the neteventebpfext driver tests on 1ES runners.
neteventebpfext_driver_tests:
# Always run this job.
needs: regular
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
if: github.repository == 'microsoft/ntosebpfext' && (github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/reusable-test.yml
strategy:
matrix:
image:
- server2022
- server2025
with:
name: neteventebpfext driver tests
pre_test: powershell -file .\bin\process_monitor.Tests\win-x64\Install-eBpfForWindows.ps1 1.4.0
test_command: .\neteventebpfext_driver_test.exe -d yes
name: neteventebpfext_driver_${{ matrix.image }}
pre_test: .\setup_ebpf_cicd_tests.ps1 -KmTracing $false
test_command: .\execute_ebpf_cicd_tests.ps1 -TestMode "CI/CD" -Options @("neteventebpfext")
post_test: .\cleanup_ebpf_cicd_tests.ps1 -KmTracing $false
build_artifact: Build-x64
environment: windows-2025
code_coverage: true
gather_dumps: true
capture_etw: true
leak_detection: true
environment: '["self-hosted", "1ES.Pool=ebpf-extensions-cicd-runner-pool", "1ES.ImageOverride=${{ matrix.image }}_v2", "JobId=netevent-driver-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}-${{ strategy.job-index }}-{0}"]'
code_coverage: false
gather_dumps: false
capture_etw: false

# Run the ntosebpfext driver tests in GitHub.
# Run the ntosebpfext driver tests on 1ES runners.
ntosebpfext_driver_tests:
# Always run this job.
needs: regular
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
if: github.repository == 'microsoft/ntosebpfext' && (github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/reusable-test.yml
strategy:
matrix:
image:
- server2022
- server2025
with:
name: ntosebpfext driver tests
pre_test: powershell -file .\bin\process_monitor.Tests\win-x64\Install-eBpfForWindows.ps1 1.4.0
test_command: .\ntosebpfext_driver_test.exe -d yes
name: ntosebpfext_driver_${{ matrix.image }}
pre_test: .\setup_ebpf_cicd_tests.ps1 -KmTracing $false
test_command: .\execute_ebpf_cicd_tests.ps1 -TestMode "CI/CD" -Options @("ntosebpfext")
post_test: .\cleanup_ebpf_cicd_tests.ps1 -KmTracing $false
build_artifact: Build-x64
environment: windows-2025
code_coverage: true
gather_dumps: true
capture_etw: true
leak_detection: true
environment: '["self-hosted", "1ES.Pool=ebpf-extensions-cicd-runner-pool", "1ES.ImageOverride=${{ matrix.image }}_v2", "JobId=ntos-driver-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}-${{ strategy.job-index }}-{0}"]'
code_coverage: false
gather_dumps: false
capture_etw: false

ossar:
# Always run this job.
Expand Down
39 changes: 39 additions & 0 deletions .github/workflows/reusable-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,45 @@ jobs:
working-directory: ${{env.GITHUB_WORKSPACE}}
run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} /p:Platform=${{env.BUILD_PLATFORM}} /bl:${{env.BUILD_PLATFORM}}_${{env.BUILD_CONFIGURATION}}\build_logs\build.binlog ${{env.BUILD_OPTIONS}} ${{env.SOLUTION_FILE_PATH}}

- name: Add eBPF for Windows installer to VM test payload
if: steps.skip_check.outputs.should_skip != 'true' && inputs.build_artifact == 'Build-x64'
working-directory: ${{github.workspace}}
run: |
.\scripts\Install-eBpfForWindows.ps1 `
-version 1.4.0 `
-DestinationPath "${{env.BUILD_PLATFORM}}\${{env.BUILD_CONFIGURATION}}\ebpf-for-windows.msi" `
-DownloadOnly

- name: Verify VM test payload
if: steps.skip_check.outputs.should_skip != 'true' && inputs.build_artifact == 'Build-x64'
working-directory: ${{github.workspace}}
run: |
$output = "${{env.BUILD_PLATFORM}}\${{env.BUILD_CONFIGURATION}}"
$requiredFiles = @(
"ntosebpfext_driver_test.exe",
"neteventebpfext_driver_test.exe",
"ntosebpfext.sys",
"neteventebpfext.sys",
"netevent_sim.sys",
"NtosEbpfExt.inf",
"NetEventEbpfExt.inf",
"ebpf-for-windows.msi",
"common.psm1",
"config_test_vm.psm1",
"tracing_utils.psm1",
"setup_ebpf_cicd_tests.ps1",
"execute_ebpf_cicd_tests.ps1",
"cleanup_ebpf_cicd_tests.ps1",
"install_ebpf.psm1",
"run_driver_tests.psm1",
"vm_run_tests.psm1",
"test_execution.json"
)
$missingFiles = $requiredFiles | Where-Object { -not (Test-Path (Join-Path $output $_)) }
if ($missingFiles) {
throw "Missing required VM test payload files: $($missingFiles -join ', ')"
}

- name: Zip Build Output
if: always() && (steps.skip_check.outputs.should_skip != 'true')
working-directory: ${{github.workspace}}
Expand Down
116 changes: 103 additions & 13 deletions .github/workflows/reusable-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ permissions:

jobs:
run_test:
# Due to app-verifier, unit tests take a lot longer to execute. Increase the timeout to 90 minutes.
timeout-minutes: 90
# VM-backed driver tests can include VM recovery and dump collection.
timeout-minutes: 150

strategy:
matrix:
configurations: ${{ fromJSON(inputs.configurations) }}
runs-on: ${{inputs.environment}}
runs-on: ${{ fromJSON(format(inputs.environment, strategy.job-index)) }}
env:
# Configuration type to build.
SOURCE_ROOT: ${{github.workspace}}
Expand Down Expand Up @@ -101,11 +101,16 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# Check out source code if code coverage is being gathered or if crash dumps
# (which require ProcDump downloaded via the repo scripts) are being gathered.
if: ((inputs.code_coverage == true) || (inputs.gather_dumps == true)) && (steps.skip_check.outputs.should_skip != 'true')
if: ((inputs.code_coverage == true) || (inputs.gather_dumps == true)) && !contains(inputs.environment, '1ES') && (steps.skip_check.outputs.should_skip != 'true')
with:
submodules: 'recursive'
ref: ${{ github.event.workflow_run.head_branch }}

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
if: contains(inputs.environment, '1ES') && (steps.skip_check.outputs.should_skip != 'true')
with:
ref: ${{ github.event.workflow_run.head_branch }}

- name: Install ProcDump
id: install_procdump
if: (inputs.gather_dumps == true) && (steps.skip_check.outputs.should_skip != 'true')
Expand Down Expand Up @@ -143,7 +148,7 @@ jobs:

- name: Set up OpenCppCoverage and add to PATH
id: set_up_opencppcoverage
if: (inputs.code_coverage == true) && (inputs.environment != 'ebpf_cicd_tests_ws2019' && inputs.environment != 'ebpf_cicd_tests_ws2022' && inputs.environment != 'ebpf_cicd_perf_ws2022') && (steps.skip_check.outputs.should_skip != 'true')
if: (inputs.code_coverage == true) && !contains(inputs.environment, '1ES') && (inputs.environment != 'ebpf_cicd_tests_ws2019' && inputs.environment != 'ebpf_cicd_tests_ws2022' && inputs.environment != 'ebpf_cicd_perf_ws2022') && (steps.skip_check.outputs.should_skip != 'true')
run: |
$curlDependencies = Get-Content -Raw "${{github.workspace}}\.github\curl-dependencies.json" | ConvertFrom-Json
$version = $curlDependencies.opencppcoverage.version
Expand Down Expand Up @@ -176,7 +181,7 @@ jobs:
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" -Name "DumpFolder" -Value "$dump_path" -PropertyType ExpandString -ErrorAction SilentlyContinue

- name: Remove existing artifacts
if: (inputs.environment == 'ebpf_cicd_tests_ws2019' || inputs.environment == 'ebpf_cicd_tests_ws2022' || inputs.environment == 'ebpf_cicd_perf_ws2022') && (steps.skip_check.outputs.should_skip != 'true')
if: (contains(inputs.environment, 'ebpf_cicd') || contains(inputs.environment, '1ES')) && (steps.skip_check.outputs.should_skip != 'true')
run: |
Remove-Item -Path ${{github.workspace}}\${{env.BUILD_PLATFORM}}\${{env.BUILD_CONFIGURATION}} -Recurse -Force -ErrorAction SilentlyContinue

Expand Down Expand Up @@ -221,12 +226,75 @@ jobs:
.\netevent_ebpf_ext_export_program_info.exe

- name: Run pre test command
if: steps.skip_check.outputs.should_skip != 'true' && (inputs.environment != 'ebpf_cicd_tests_ws2019' && inputs.environment != 'ebpf_cicd_tests_ws2022' && inputs.environment != 'ebpf_cicd_perf_ws2022')
if: steps.skip_check.outputs.should_skip != 'true' && !contains(inputs.environment, '1ES') && (inputs.environment != 'ebpf_cicd_tests_ws2019' && inputs.environment != 'ebpf_cicd_tests_ws2022' && inputs.environment != 'ebpf_cicd_perf_ws2022')
id: run_pre_test_command
working-directory: ./${{env.BUILD_PLATFORM}}/${{env.BUILD_CONFIGURATION}}
run: |
${{env.PRE_COMMAND}}

- name: Diagnose nested Hyper-V
if: steps.skip_check.outputs.should_skip != 'true' && contains(inputs.environment, '1ES')
continue-on-error: true
run: |
$ErrorActionPreference = 'Continue'

Get-ComputerInfo |
Select-Object CsName, WindowsProductName, OsBuildNumber, HyperVisorPresent |
Format-List

Get-CimInstance Win32_Processor |
Select-Object Name, VirtualizationFirmwareEnabled, VMMonitorModeExtensions, SecondLevelAddressTranslationExtensions |
Format-List

Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All |
Format-List FeatureName, State
Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-Management-PowerShell |
Format-List FeatureName, State

Get-Service vmms, vmcompute -ErrorAction Continue |
Format-Table Name, Status, StartType

Get-CimInstance Win32_SystemDriver -Filter "Name = 'Vid'" |
Format-List Name, State, Status, StartMode, PathName

bcdedit /enum '{current}' |
Select-String hypervisorlaunchtype

Get-VMHost | Format-List *
Get-VM -Name runner_vm | Format-List *
Get-VMProcessor -VMName runner_vm | Format-List *
Get-VMSnapshot -VMName runner_vm | Format-Table Name, SnapshotType

- name: Run pre test command on 1ES runner
if: steps.skip_check.outputs.should_skip != 'true' && contains(inputs.environment, '1ES')
id: run_pre_test_command_1es
working-directory: ./${{env.BUILD_PLATFORM}}/${{env.BUILD_CONFIGURATION}}
run: |
${{env.PRE_COMMAND}} -LogFileName ${{ runner.name }}.log -SelfHostedRunnerName '1ESRunner' -RegressionArtifactsConfiguration ${{env.BUILD_CONFIGURATION}}

- name: Diagnose nested Hyper-V failure
if: failure() && contains(inputs.environment, '1ES') && steps.run_pre_test_command_1es.outcome == 'failure'
continue-on-error: true
run: |
$ErrorActionPreference = 'Continue'
$startTime = (Get-Date).AddMinutes(-15)
$logs = @(
'Microsoft-Windows-Hyper-V-Hypervisor-Admin',
'Microsoft-Windows-Hyper-V-VMMS-Admin',
'Microsoft-Windows-Hyper-V-Worker-Admin',
'System'
)

foreach ($log in $logs) {
Write-Host "`n=== $log ==="
Get-WinEvent -FilterHashtable @{
LogName = $log
StartTime = $startTime
} -ErrorAction Continue |
Select-Object -First 50 TimeCreated, Id, LevelDisplayName, ProviderName, Message |
Format-List
}

- name: Run test with Code Coverage and low resource simulation
if: (inputs.code_coverage == true) && (inputs.fault_injection == true) && (steps.skip_check.outputs.should_skip != 'true')
id: run_test_with_code_coverage_in_fault_injection
Expand All @@ -253,22 +321,36 @@ jobs:
OpenCppCoverage.exe -q --sources %CD% --excluded_sources %CD%\external\Catch2 --export_type cobertura:ebpf_for_windows.xml --working_dir ${{env.BUILD_PLATFORM}}\${{env.BUILD_CONFIGURATION}} -- powershell .\Run-Test.ps1 ${{env.DUMP_PATH}} ${{env.TEST_TIMEOUT}} ${{env.TEST_COMMAND}}

- name: Run test without codecoverage
if: (inputs.code_coverage != true) && (inputs.vs_dev != true) && (inputs.fault_injection != true) && (steps.skip_check.outputs.should_skip != 'true')
if: (inputs.code_coverage != true) && (inputs.vs_dev != true) && (inputs.fault_injection != true) && !contains(inputs.environment, '1ES') && (steps.skip_check.outputs.should_skip != 'true')
working-directory: ./${{env.BUILD_PLATFORM}}/${{env.BUILD_CONFIGURATION}}
id: run_test_without_code_coverage
shell: cmd
run: |
set EBPF_ENABLE_WER_REPORT=yes
${{env.TEST_COMMAND}}

- name: Run test on 1ES runner
if: (inputs.code_coverage == false) && (steps.skip_check.outputs.should_skip != 'true') && contains(inputs.environment, '1ES') && (inputs.fault_injection != true)
id: run_test_1es
working-directory: ./${{env.BUILD_PLATFORM}}/${{env.BUILD_CONFIGURATION}}
run: |
${{env.TEST_COMMAND}} -LogFileName ${{ runner.name }}.log -SelfHostedRunnerName '1ESRunner' -TestJobTimeout ${{env.TEST_TIMEOUT}}

- name: Run post test command
# Run the post test command even if the workflow has failed.
if: (success() || failure()) && (steps.skip_check.outputs.should_skip != 'true') && (inputs.environment != 'ebpf_cicd_tests_ws2019' && inputs.environment != 'ebpf_cicd_tests_ws2022' && inputs.environment != 'ebpf_cicd_perf_ws2022')
if: (success() || failure()) && (steps.skip_check.outputs.should_skip != 'true') && !contains(inputs.environment, '1ES') && (inputs.environment != 'ebpf_cicd_tests_ws2019' && inputs.environment != 'ebpf_cicd_tests_ws2022' && inputs.environment != 'ebpf_cicd_perf_ws2022')
id: run_post_test_command
working-directory: ./${{env.BUILD_PLATFORM}}/${{env.BUILD_CONFIGURATION}}
run: |
${{env.POST_COMMAND}}

- name: Run post test command on 1ES runner
if: (success() || failure()) && (steps.skip_check.outputs.should_skip != 'true') && contains(inputs.environment, '1ES')
id: run_post_test_command_1es
working-directory: ./${{env.BUILD_PLATFORM}}/${{env.BUILD_CONFIGURATION}}
run: |
${{env.POST_COMMAND}} -LogFileName ${{ runner.name }}.log -SelfHostedRunnerName '1ESRunner'

- name: Check for CodeCoverage
if: steps.skip_check.outputs.should_skip != 'true'
uses: andstor/file-existence-action@558493d6c74bf472d87c84eab196434afc2fa029
Expand Down Expand Up @@ -335,10 +417,10 @@ jobs:
- name: Fail if code coverage upload fails
if: (steps.skip_check.outputs.should_skip != 'true')
run: |
if ($${{ steps.test.upload_code_coverage_report_1!='failure' }}) { exit 0 }
if ($${{ steps.test.upload_code_coverage_report_2!='failure' }}) { exit 0 }
if ($${{ steps.test.upload_code_coverage_report_3!='failure' }}) { exit 0 }
if ($${{ steps.test.upload_code_coverage_report_4!='failure' }}) { exit 0 }
if ($${{ steps.upload_code_coverage_report_1.outcome != 'failure' }}) { exit 0 }
if ($${{ steps.upload_code_coverage_report_2.outcome != 'failure' }}) { exit 0 }
if ($${{ steps.upload_code_coverage_report_3.outcome != 'failure' }}) { exit 0 }
if ($${{ steps.upload_code_coverage_report_4.outcome != 'failure' }}) { exit 0 }
exit 1

- name: Stop ETW tracing
Expand Down Expand Up @@ -385,6 +467,14 @@ jobs:
path: ./${{env.BUILD_PLATFORM}}/${{env.BUILD_CONFIGURATION}}/TestLogs
retention-days: 5

- name: Check for generated artifacts
# Check for artifacts even if the workflow failed.
if: (success() || failure()) && (steps.skip_check.outputs.should_skip != 'true')
uses: andstor/file-existence-action@558493d6c74bf472d87c84eab196434afc2fa029
id: check_artifacts
with:
files: ${{github.workspace}}\${{env.BUILD_PLATFORM}}\${{env.BUILD_CONFIGURATION}}\Artifacts\*

- name: Upload generated artifacts
# Upload artifacts even if the workflow failed.
if: (success() || failure()) && (steps.skip_check.outputs.should_skip != 'true') && (steps.check_artifacts.outputs.files_exists == 'true')
Expand Down
22 changes: 19 additions & 3 deletions scripts/Install-eBpfForWindows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,34 @@

# Define one parameter that takes the version of eBPF for Windows to install
param(
[string]$version
[Parameter(Mandatory = $true)]
[string]$version,

[string]$DestinationPath = "$env:TEMP\ebpf-for-windows.$version.msi",

[switch]$DownloadOnly
)

# Define the URL to download the eBPF for Windows installer
$installer_url = "https://github.com/microsoft/ebpf-for-windows/releases/download/v%%VER%%/ebpf-for-windows.x64.%%VER%%.msi"
$installer_url = $installer_url -replace "%%VER%%", $version

# Define the path to download the eBPF for Windows installer
$installer_path = "$env:TEMP\ebpf-for-windows.$version.msi"
$installer_path = $DestinationPath

# Download the eBPF for Windows installer
Invoke-WebRequest -Uri $installer_url -OutFile $installer_path

if (-not (Test-Path $installer_path -PathType Leaf)) {
throw "Failed to download the eBPF for Windows installer to '$installer_path'."
}

if ($DownloadOnly) {
return
}

# Install eBPF for Windows
Start-Process -FilePath msiexec -ArgumentList "/i $installer_path /quiet" -Wait
$process = Start-Process -FilePath msiexec -ArgumentList "/i `"$installer_path`" /quiet /norestart" -Wait -PassThru
if ($process.ExitCode -notin @(0, 3010)) {
throw "eBPF for Windows installation failed with exit code $($process.ExitCode)."
}
Loading
Loading