clients::rdp connects over any caller-dialled TCP stream (direct, proxy or SSH tunnel), upgrades to TLS and logs on with NLA (CredSSP/NTLM), optionally falling back to TLS-only logon for servers without NLA such as xrdp (credentials are passed so they log straight in). The server certificate is pinned through a caller check on its SHA256 fingerprint before any credentials are sent. The desktop decodes into the VNC client's RGBA framebuffer; input (IronRDP's scancode/Unicode/mouse operations), Display Control resizes and the deactivation-reactivation sequence run on the session thread. IronRDP's releases need three vendored patches (vendor/README.md): picky and sspi with their RustCrypto release-candidate pins relaxed so they share russh's stable versions (their own suites, 402 tests, pass against them), and ironrdp-session with two unreleased upstream bitmap fixes (#1486 stride, #1524 RDP6 orientation) without which xrdp desktops render sheared. Verified live against xrdp (scottyhardy/docker-remote-desktop): logon, full desktop rendering, keyboard and mouse input.
323 lines
9.9 KiB
YAML
323 lines
9.9 KiB
YAML
name: Publish NuGet package
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
dry-run:
|
|
description: 'Dry run'
|
|
required: true
|
|
type: boolean
|
|
default: true
|
|
version:
|
|
description: 'Package version'
|
|
default: "latest"
|
|
required: true
|
|
schedule:
|
|
- cron: '21 3 * * 1' # 3:21 AM UTC every Monday
|
|
|
|
jobs:
|
|
preflight:
|
|
name: Preflight
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
dry-run: ${{ steps.get-dry-run.outputs.dry-run }}
|
|
package-version: ${{ steps.info.outputs.package-version }}
|
|
|
|
steps:
|
|
- name: Get dry run
|
|
id: get-dry-run
|
|
shell: pwsh
|
|
run: |
|
|
Set-PSDebug -Trace 1
|
|
|
|
$IsDryRun = '${{ github.event.inputs.dry-run }}' -Eq 'true' -Or '${{ github.event_name }}' -Eq 'schedule'
|
|
|
|
if ($IsDryRun) {
|
|
echo "dry-run=true" >> $Env:GITHUB_OUTPUT
|
|
} else {
|
|
echo "dry-run=false" >> $Env:GITHUB_OUTPUT
|
|
}
|
|
|
|
- name: Package information
|
|
id: info
|
|
shell: pwsh
|
|
run: |
|
|
$PackageVersion = '${{ inputs.version }}'
|
|
if ([string]::IsNullOrEmpty($PackageVersion) -or $PackageVersion -eq 'latest') {
|
|
$PackageVersion = (Get-Date -Format "yyyy.MM.dd") + ".0"
|
|
}
|
|
|
|
if ($PackageVersion -NotMatch '^\d+\.\d+\.\d+\.\d+$') {
|
|
throw "invalid version format: $PackageVersion, expected: 1.2.3.4"
|
|
}
|
|
|
|
echo "package-version=$PackageVersion" >> $Env:GITHUB_OUTPUT
|
|
echo "::notice::Version: $PackageVersion"
|
|
|
|
build-native:
|
|
uses: ./.github/workflows/build-native.yml
|
|
|
|
build-managed:
|
|
name: Managed build
|
|
runs-on: windows-2022
|
|
needs: [ preflight, build-native ]
|
|
|
|
steps:
|
|
- name: Check out ${{ github.repository }}
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Prepare dependencies
|
|
shell: pwsh
|
|
run: |
|
|
New-Item -ItemType Directory -Path "dependencies/runtimes" | Out-Null
|
|
|
|
- name: Download native components
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
path: dependencies/runtimes
|
|
|
|
- name: Rename dependencies
|
|
shell: pwsh
|
|
run: |
|
|
Set-PSDebug -Trace 1
|
|
|
|
Set-Location "dependencies/runtimes"
|
|
|
|
$(Get-Item ".\sspi-*-release") | ForEach-Object { Rename-Item $_ $_.Name.Replace("-release", "") }
|
|
$(Get-Item ".\sspi-*") | ForEach-Object { Rename-Item $_ $_.Name.Replace("sspi-", "") }
|
|
Get-ChildItem * -Recurse
|
|
|
|
- name: Set package version
|
|
shell: pwsh
|
|
run: |
|
|
$PackageVersion = '${{ needs.preflight.outputs.package-version }}'
|
|
$csprojPath = "ffi\dotnet\Devolutions.Sspi\Devolutions.Sspi.csproj"
|
|
$csprojContent = Get-Content $csprojPath -Raw
|
|
$csprojContent = $csprojContent -Replace '(<Version>).*?(</Version>)', "<Version>$PackageVersion</Version>"
|
|
Set-Content -Path $csprojPath -Value $csprojContent -Encoding UTF8
|
|
|
|
- name: Build sspi (managed)
|
|
shell: pwsh
|
|
run: |
|
|
dotnet build .\ffi\dotnet\Devolutions.Sspi\Devolutions.Sspi.csproj -o package
|
|
|
|
- name: Upload managed components
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: sspi-nupkg
|
|
path: package/*.nupkg
|
|
|
|
publish:
|
|
name: Publish NuGet package
|
|
runs-on: ubuntu-latest
|
|
environment: nuget-publish
|
|
if: needs.preflight.outputs.dry-run == 'false'
|
|
needs:
|
|
- preflight
|
|
- build-managed
|
|
permissions:
|
|
id-token: write
|
|
|
|
steps:
|
|
- name: Download NuGet package artifact
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
name: sspi-nupkg
|
|
path: package
|
|
|
|
- name: NuGet login (OIDC)
|
|
uses: NuGet/login@v1
|
|
id: nuget-login
|
|
with:
|
|
user: ${{ secrets.NUGET_BOT_USERNAME }}
|
|
|
|
- name: Publish to nuget.org
|
|
shell: pwsh
|
|
run: |
|
|
Set-PSDebug -Trace 1
|
|
|
|
$Files = Get-ChildItem -Recurse package/*.nupkg
|
|
|
|
foreach ($File in $Files) {
|
|
$PushCmd = @(
|
|
'dotnet',
|
|
'nuget',
|
|
'push',
|
|
"$File",
|
|
'--api-key',
|
|
'${{ steps.nuget-login.outputs.NUGET_API_KEY }}',
|
|
'--source',
|
|
'https://api.nuget.org/v3/index.json',
|
|
'--skip-duplicate'
|
|
)
|
|
|
|
Write-Host "Publishing $($File.Name)..."
|
|
$PushCmd = $PushCmd -Join ' '
|
|
Invoke-Expression $PushCmd
|
|
}
|
|
|
|
package-symbols:
|
|
name: Package debug symbols
|
|
runs-on: ubuntu-latest
|
|
needs: [ preflight, build-native ]
|
|
|
|
steps:
|
|
- name: Download all symbol artifacts
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
path: artifacts
|
|
pattern: sspi-*-release-symbols
|
|
|
|
- name: Package symbols into zip
|
|
shell: pwsh
|
|
run: |
|
|
Set-PSDebug -Trace 1
|
|
|
|
$PackageVersion = '${{ needs.preflight.outputs.package-version }}'
|
|
$SymbolsDir = "symbols"
|
|
New-Item -ItemType Directory -Path $SymbolsDir -Force | Out-Null
|
|
|
|
# Organize symbols by RID
|
|
$SymbolArtifacts = Get-ChildItem -Directory "artifacts" -Filter "sspi-*-release-symbols"
|
|
foreach ($Artifact in $SymbolArtifacts) {
|
|
# Extract RID from artifact name (e.g., sspi-win-x64-release-symbols -> win-x64)
|
|
$Rid = $Artifact.Name -Replace '^sspi-(.+)-release-symbols$', '$1'
|
|
$DestDir = Join-Path $SymbolsDir $Rid
|
|
New-Item -ItemType Directory -Path $DestDir -Force | Out-Null
|
|
|
|
# Copy all contents from the artifact
|
|
Get-ChildItem -Path $Artifact.FullName -Recurse | ForEach-Object {
|
|
if (-not $_.PSIsContainer) {
|
|
$RelativePath = $_.FullName.Substring($Artifact.FullName.Length + 1)
|
|
$DestPath = Join-Path $DestDir $RelativePath
|
|
$DestParent = Split-Path $DestPath -Parent
|
|
if (-not (Test-Path $DestParent)) {
|
|
New-Item -ItemType Directory -Path $DestParent -Force | Out-Null
|
|
}
|
|
Copy-Item $_.FullName $DestPath
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host "Symbol directory structure:"
|
|
Get-ChildItem -Recurse $SymbolsDir | ForEach-Object { Write-Host $_.FullName }
|
|
|
|
# Create the zip file
|
|
$ZipName = "Devolutions.Sspi.$PackageVersion.symbols.zip"
|
|
Compress-Archive -Path "$SymbolsDir/*" -DestinationPath $ZipName -Force
|
|
Write-Host "Created symbols archive: $ZipName"
|
|
|
|
- name: Upload symbols zip
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: sspi-symbols-zip
|
|
path: Devolutions.Sspi.*.symbols.zip
|
|
|
|
create-release:
|
|
name: Create GitHub Release
|
|
runs-on: ubuntu-latest
|
|
if: needs.preflight.outputs.dry-run == 'false'
|
|
needs:
|
|
- preflight
|
|
- build-managed
|
|
- package-symbols
|
|
- publish
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Download NuGet package
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
name: sspi-nupkg
|
|
path: release-assets
|
|
|
|
- name: Download symbols zip
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
name: sspi-symbols-zip
|
|
path: release-assets
|
|
|
|
- name: Create GitHub Release
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
GH_REPO: ${{ github.repository }}
|
|
shell: pwsh
|
|
run: |
|
|
Set-PSDebug -Trace 1
|
|
|
|
$PackageVersion = '${{ needs.preflight.outputs.package-version }}'
|
|
$TagName = "v$PackageVersion"
|
|
$ReleaseName = "Devolutions.Sspi $PackageVersion"
|
|
|
|
# Get the list of assets to upload
|
|
$Assets = Get-ChildItem -Path "release-assets" -File
|
|
Write-Host "Release assets:"
|
|
$Assets | ForEach-Object { Write-Host " - $($_.Name)" }
|
|
|
|
# Build the release notes
|
|
$ReleaseNotes = @"
|
|
## Devolutions.Sspi $PackageVersion
|
|
|
|
### NuGet Package
|
|
- [Devolutions.Sspi on NuGet.org](https://www.nuget.org/packages/Devolutions.Sspi/$PackageVersion)
|
|
|
|
### Included Platforms
|
|
- Windows (x64, arm64)
|
|
- macOS (x64, arm64, universal)
|
|
- Linux (x64, arm64)
|
|
- iOS device (arm64)
|
|
- iOS Simulator (arm64)
|
|
- Android (x86, x64, arm, arm64)
|
|
|
|
### Debug Symbols
|
|
The `Devolutions.Sspi.$PackageVersion.symbols.zip` archive contains debug symbols for all platforms:
|
|
- Windows: `.pdb` files
|
|
- macOS/iOS: `.dSYM` bundles
|
|
- Linux/Android: `.debug` or `.dwp` files
|
|
"@
|
|
|
|
# Create the release with assets
|
|
$AssetArgs = @()
|
|
foreach ($Asset in $Assets) {
|
|
$AssetArgs += $Asset.FullName
|
|
}
|
|
|
|
gh release create $TagName `
|
|
--title $ReleaseName `
|
|
--notes $ReleaseNotes `
|
|
--target ${{ github.sha }} `
|
|
@AssetArgs
|
|
|
|
Write-Host "Created release: $ReleaseName with tag $TagName"
|
|
|
|
notify:
|
|
name: Notify failure
|
|
runs-on: ubuntu-latest
|
|
if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }}
|
|
needs:
|
|
- preflight
|
|
- build-native
|
|
- build-managed
|
|
- package-symbols
|
|
env:
|
|
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_ARCHITECTURE }}
|
|
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
|
steps:
|
|
- name: Send slack notification
|
|
id: slack
|
|
uses: slackapi/slack-github-action@v1.26.0
|
|
with:
|
|
payload: |
|
|
{
|
|
"blocks": [
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*${{ github.repository }}* :fire::fire::fire::fire::fire: \n The scheduled build for *${{ github.repository }}* is <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|broken>"
|
|
}
|
|
}
|
|
]
|
|
}
|