Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a936601
Package and export the Windows CEF sandbox
summeroff Sep 18, 2026
466602e
Apply CMake formatting
summeroff Sep 18, 2026
5eebdb2
Skip oversized CEF PDB in symbol upload
summeroff Sep 19, 2026
603f8fa
Make CEF sandbox gating generator independent
summeroff Sep 20, 2026
98cc448
Update obs-browser sandbox hardening
summeroff Sep 20, 2026
6ea2a7c
Fix obs-browser submodule revision
summeroff Sep 20, 2026
f6141a5
Update obs-browser CI hardening
summeroff Sep 20, 2026
488e9eb
Update Windows x64 to CEF 6613
summeroff Sep 18, 2026
22652cc
Publish stripped CEF symbols to the symbol server
summeroff Sep 20, 2026
831c294
Add compatible CEF PDB relink helper
summeroff Sep 20, 2026
343b64d
Harden CEF relink output validation
summeroff Sep 20, 2026
181e6ae
Align workflow metadata with CEF 6613
summeroff Oct 1, 2026
5cc79ea
Address CEF sandbox review feedback
summeroff Oct 2, 2026
58a66c5
Update obs-browser submodule to ABI logging fix
summeroff Oct 2, 2026
526478a
cmake: refresh CEF discovery when selected dependency changes
summeroff Oct 2, 2026
b0ffe74
cmake: align CEF sandbox exports with package layout
summeroff Oct 2, 2026
2d6a813
Guard CEF PDB output aliases and retain explicit cache overrides
summeroff Oct 2, 2026
7156c0a
cmake: restore libobs package prefix after dependencies
summeroff Oct 2, 2026
e12b0da
deps: pin Windows x64 CEF 6613 revision 3
summeroff Oct 7, 2026
fc6d947
ci: select CEF 6613 revision 3 in legacy Windows jobs
summeroff Oct 7, 2026
d593d09
Point obs-browser at merged sandbox change
summeroff Oct 14, 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
45 changes: 45 additions & 0 deletions .github/actions/streamlabs-windows-artifacts/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,51 @@ runs:
$kept = 0
$skipped = 0

if ('${{ inputs.target }}' -eq 'x64') {
$presets = Get-Content -LiteralPath 'CMakePresets.json' -Raw | ConvertFrom-Json
$dependencyPreset = $presets.configurePresets | Where-Object name -eq 'dependencies'
$cefDependency = $dependencyPreset.vendor.'obsproject.com/obs-studio'.dependencies.cef
$cefVersion = [string]$cefDependency.version
if ($cefDependency.versions -And $cefDependency.versions.'windows-x64') {
$cefVersion = [string]$cefDependency.versions.'windows-x64'
}
$cefHash = [string]$cefDependency.hashes.'windows-x64'
$cefRootPath = Join-Path '.deps' "cef_binary_${cefVersion}_windows_x64"
if (-Not (Test-Path -LiteralPath $cefRootPath -PathType Container)) {
throw "The configured Windows x64 CEF dependency directory is missing: $cefRootPath"
}
$cefRoot = Get-Item -LiteralPath $cefRootPath

$installedCefHash = (Get-Content -LiteralPath '.deps/.dependency_cef_x64.sha256' -Raw).Trim()
if ($installedCefHash -ne $cefHash) {
throw "The extracted CEF dependency hash does not match CMakePresets.json"
}

$cefVersionHeader = Join-Path $cefRoot.FullName 'include/cef_version.h'
$cefBuild = Select-String -LiteralPath $cefVersionHeader -Pattern '^#define CHROME_VERSION_BUILD ([0-9]+)$'
if (-Not $cefBuild -Or $cefBuild.Matches[0].Groups[1].Value -ne $cefVersion) {
throw "CEF version header does not identify configured Chromium build $cefVersion"
}

$expectedCefPdbs = @(
'Release/chrome_elf.dll.pdb',
'Release/dxcompiler.dll.pdb',
'Release/libcef.dll.pdb',
'Release/libEGL.dll.pdb',
'Release/libGLESv2.dll.pdb',
'Release/vk_swiftshader.dll.pdb',
'Release/vulkan-1.dll.pdb',
'build/libcef_dll_wrapper/Release/libcef_dll_wrapper.pdb'
)
foreach ($relativePath in $expectedCefPdbs) {
$pdbPath = Join-Path $cefRoot.FullName $relativePath
if (-Not (Test-Path -LiteralPath $pdbPath -PathType Leaf)) {
throw "The CEF runtime dependency is missing required symbol file: $relativePath"
}
}
Write-Host "Validated all $($expectedCefPdbs.Count) embedded CEF PDBs in $($cefRoot.Name)"
}

# The relative layout is preserved so the symbol server job can still report which pdb's
# share a file name when it flattens them
foreach ($searchPath in @("build_${{ inputs.target }}", '.deps')) {
Expand Down
6 changes: 5 additions & 1 deletion .github/actions/upload-debug-symbols/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ inputs:
description: "Comma separated folders to search for pdb's. Defaults to the whole workspace."
required: false
default: ""
excludePdbNames:
description: "Comma separated pdb file names or wildcard patterns to exclude."
required: false
default: ""
forceUpload:
description: "Upload every pdb instead of skipping the ones the symbol store already has."
required: false
Expand Down Expand Up @@ -59,7 +63,7 @@ runs:
- name: Run symbol server scripts
if: runner.os != 'macOS'
shell: powershell
run: ./symsrv-scripts/main.bat "${{ inputs.githubWorkspace }}/symsrv-scripts" ".\main.ps1 -localSourceDir '${{ inputs.githubWorkspace }}' -repo_userId '${{ inputs.repoUserId }}' -repo_name '${{ inputs.repoName }}' -repo_branch '${{ inputs.repoBranch }}'${{ inputs.pdbPaths != '' && format(' -pdbPaths ''{0}''', inputs.pdbPaths) || '' }}${{ fromJSON(inputs.forceUpload) && ' -forceUpload' || '' }} -subModules 'plugins/mediasoup-connector,stream-labs,mediasoup-connector,streamlabs;plugins/enc-amf,stream-labs,obs-amd-encoder,streamlabs;plugins/motion-effect,stream-labs,motion-effect,master;plugins/obs-browser,stream-labs,obs-browser,streamlabs;plugins/obs-ndi,stream-labs,obs-ndi,streamlabs;plugins/obs-ndi,stream-labs,obs-amd-encoder,streamlabs;plugins/obs-openvr,stream-labs,OBS-OpenVR-Input-Plugin,master;plugins/sl-vst,stream-labs,sl-vst,streamlabs;plugins/slobs-virtual-cam,stream-labs,slobs-virtual-cam,streamlabs;plugins/win-dshow/libdshowcapture,stream-labs,libdshowcapture,streamlabs'"
run: ./symsrv-scripts/main.bat "${{ inputs.githubWorkspace }}/symsrv-scripts" ".\main.ps1 -localSourceDir '${{ inputs.githubWorkspace }}' -repo_userId '${{ inputs.repoUserId }}' -repo_name '${{ inputs.repoName }}' -repo_branch '${{ inputs.repoBranch }}'${{ inputs.pdbPaths != '' && format(' -pdbPaths ''{0}''', inputs.pdbPaths) || '' }}${{ inputs.excludePdbNames != '' && format(' -excludePdbNames ''{0}''', inputs.excludePdbNames) || '' }}${{ fromJSON(inputs.forceUpload) && ' -forceUpload' || '' }} -subModules 'plugins/mediasoup-connector,stream-labs,mediasoup-connector,streamlabs;plugins/enc-amf,stream-labs,obs-amd-encoder,streamlabs;plugins/motion-effect,stream-labs,motion-effect,master;plugins/obs-browser,stream-labs,obs-browser,streamlabs;plugins/obs-ndi,stream-labs,obs-ndi,streamlabs;plugins/obs-ndi,stream-labs,obs-amd-encoder,streamlabs;plugins/obs-openvr,stream-labs,OBS-OpenVR-Input-Plugin,master;plugins/sl-vst,stream-labs,sl-vst,streamlabs;plugins/slobs-virtual-cam,stream-labs,slobs-virtual-cam,streamlabs;plugins/win-dshow/libdshowcapture,stream-labs,libdshowcapture,streamlabs'"
env:
AWS_SYMB_ACCESS_KEY_ID: ${{ inputs.awsSymbAccessKeyId }}
AWS_SYMB_SECRET_ACCESS_KEY: ${{ inputs.awsSymbSecretAccessKey }}
Expand Down
172 changes: 172 additions & 0 deletions .github/scripts/Create-CefPublicPdb.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#Requires -Version 7.2

# Chromium links libcef with lld-link. Although that linker advertises
# /PDBSTRIPPED in its help output, Chromium 128's bundled version rejects the
# option as unimplemented. Produce the equivalent matching public PDB with the
# Windows SDK's supported post-link tool instead.

[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $CefOutDirectory,

[string] $PdbCopyPath,

[string] $LlvmPdbUtilPath,

[string] $OutputPath,

[ValidateRange(1, [long]::MaxValue)]
[long] $MaximumBytes = 2147483647,

[switch] $ReplaceExisting
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

function Resolve-Executable {
param(
[Parameter(Mandatory)]
[string] $Name,

[string] $RequestedPath,

[string[]] $Candidates = @()
)

if ($RequestedPath) {
return (Resolve-Path -LiteralPath $RequestedPath).Path
}

$command = Get-Command $Name -ErrorAction SilentlyContinue
if ($command) {
return $command.Source
}

foreach ($candidate in $Candidates) {
if ($candidate -and (Test-Path -LiteralPath $candidate -PathType Leaf)) {
return (Resolve-Path -LiteralPath $candidate).Path
}
}

throw "Could not find $Name. Pass its path explicitly."
}

function Get-PdbIdentity {
param(
[Parameter(Mandatory)]
[string] $PdbPath,

[Parameter(Mandatory)]
[string] $PdbUtil
)

$summary = @(& $PdbUtil dump -summary $PdbPath 2>&1)
if ($LASTEXITCODE -ne 0) {
throw "llvm-pdbutil could not inspect '$PdbPath':`n$($summary -join "`n")"
}

$summaryText = $summary -join "`n"
$guid = [regex]::Match($summaryText, '(?m)^\s*GUID:\s*(\{[^}]+\})\s*$')
$age = [regex]::Match($summaryText, '(?m)^\s*Age:\s*(\d+)\s*$')
$stripped = [regex]::Match($summaryText, '(?m)^\s*Is stripped:\s*(true|false)\s*$')
if (-not $guid.Success -or -not $age.Success -or -not $stripped.Success) {
throw "llvm-pdbutil returned an unrecognized summary for '$PdbPath'."
}

return [pscustomobject]@{
Guid = $guid.Groups[1].Value.ToUpperInvariant()
Age = [int] $age.Groups[1].Value
IsStripped = $stripped.Groups[1].Value -eq 'true'
}
}

$cefOut = (Resolve-Path -LiteralPath $CefOutDirectory).Path
$cefRoot = (Resolve-Path -LiteralPath (Join-Path $cefOut '..')).Path
$cefSource = (Resolve-Path -LiteralPath (Join-Path $cefOut '..\..')).Path
$privatePdb = Join-Path $cefOut 'libcef.dll.pdb'
if (-not (Test-Path -LiteralPath $privatePdb -PathType Leaf)) {
throw "The CEF private PDB does not exist: $privatePdb"
}

if (-not $OutputPath) {
$OutputPath = Join-Path $cefOut 'libcef.dll.public.pdb'
} elseif (-not [System.IO.Path]::IsPathRooted($OutputPath)) {
$OutputPath = Join-Path $cefOut $OutputPath
}
$outputDirectory = Split-Path -Parent $OutputPath
if (-not (Test-Path -LiteralPath $outputDirectory -PathType Container)) {
throw "The public PDB output directory does not exist: $outputDirectory"
}
$publicPdb = [System.IO.Path]::GetFullPath($OutputPath)
if ($publicPdb -eq $privatePdb) {
throw 'The public PDB output must not overwrite the private PDB.'
}
$relativeOutput = [System.IO.Path]::GetRelativePath($cefOut, $publicPdb)
if (
[System.IO.Path]::IsPathRooted($relativeOutput) -or
$relativeOutput -eq '..' -or
$relativeOutput.StartsWith("..$([System.IO.Path]::DirectorySeparatorChar)") -or
$relativeOutput.StartsWith("..$([System.IO.Path]::AltDirectorySeparatorChar)")
) {
throw "The public PDB output must remain inside the CEF output directory: $cefOut"
}
if (Test-Path -LiteralPath $publicPdb) {
if (-not $ReplaceExisting) {
throw "The public PDB already exists. Pass -ReplaceExisting to regenerate it: $publicPdb"
}
Remove-Item -LiteralPath $publicPdb -Force
Comment thread
summeroff marked this conversation as resolved.
}

$windowsKitsPdbCopy = if (${env:ProgramFiles(x86)}) {
Join-Path ${env:ProgramFiles(x86)} 'Windows Kits\10\Debuggers\x64\pdbcopy.exe'
}
$pdbCopy = Resolve-Executable -Name 'pdbcopy.exe' -RequestedPath $PdbCopyPath -Candidates @($windowsKitsPdbCopy)
$pdbUtil = Resolve-Executable -Name 'llvm-pdbutil.exe' -RequestedPath $LlvmPdbUtilPath -Candidates @(
(Join-Path $cefSource 'third_party\llvm-build\Release+Asserts\bin\llvm-pdbutil.exe'),
(Join-Path $cefRoot 'third_party\llvm-build\Release+Asserts\bin\llvm-pdbutil.exe'),
(Join-Path $env:ProgramFiles 'LLVM\bin\llvm-pdbutil.exe'),
(Join-Path $env:ProgramFiles 'Microsoft Visual Studio\2022\Enterprise\VC\Tools\Llvm\x64\bin\llvm-pdbutil.exe'),
(Join-Path $env:ProgramFiles 'Microsoft Visual Studio\2022\Professional\VC\Tools\Llvm\x64\bin\llvm-pdbutil.exe'),
(Join-Path $env:ProgramFiles 'Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\x64\bin\llvm-pdbutil.exe'),
(Join-Path $env:ProgramFiles 'Microsoft Visual Studio\2022\BuildTools\VC\Tools\Llvm\x64\bin\llvm-pdbutil.exe')
)

$pdbCopyOutput = @(& $pdbCopy $privatePdb $publicPdb -p 2>&1)
if ($LASTEXITCODE -ne 0) {
throw (
"pdbcopy failed. Older Windows SDK versions cannot read PDBs larger than 4 GiB; " +
"rebuild CEF with symbol_level=1 first.`n$($pdbCopyOutput -join "`n")"
)
}
if (-not (Test-Path -LiteralPath $publicPdb -PathType Leaf)) {
throw "pdbcopy did not produce the requested public PDB: $publicPdb"
}

$privateIdentity = Get-PdbIdentity -PdbPath $privatePdb -PdbUtil $pdbUtil
$publicIdentity = Get-PdbIdentity -PdbPath $publicPdb -PdbUtil $pdbUtil
if ($privateIdentity.Guid -ne $publicIdentity.Guid -or $privateIdentity.Age -ne $publicIdentity.Age) {
throw 'The public PDB does not have the same GUID and age as the private PDB.'
}
if (-not $publicIdentity.IsStripped) {
throw 'The generated public PDB is not marked as stripped.'
}

$publicFile = Get-Item -LiteralPath $publicPdb
if ($publicFile.Length -gt $MaximumBytes) {
throw "The public PDB exceeds the configured size limit of $MaximumBytes bytes: $publicPdb"
}

@($privatePdb, $publicPdb) | ForEach-Object {
$item = Get-Item -LiteralPath $_
$hash = Get-FileHash -LiteralPath $_ -Algorithm SHA256
[pscustomobject]@{
Path = $item.FullName
Bytes = $item.Length
SHA256 = $hash.Hash
Guid = $privateIdentity.Guid
Age = $privateIdentity.Age
Public = $_ -eq $publicPdb
}
} | Format-Table -AutoSize
Loading
Loading