From 0c7e16e98e6602a2f31605f273b0318462e0787c Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 6 Jul 2026 10:04:28 +0000 Subject: [PATCH] chore: add PowerShell script to export GPG public key for auto-import in devcontainer --- .devcontainer/README.md | 10 +++ .devcontainer/export-signing-key.ps1 | 118 +++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 .devcontainer/export-signing-key.ps1 diff --git a/.devcontainer/README.md b/.devcontainer/README.md index f59a27cb8d..13a2dd50ea 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -104,6 +104,16 @@ So the easiest setup is: ./.devcontainer/export-signing-key.sh ``` +On Windows PowerShell, use: + +```powershell +# on the HOST, from repo root (auto-uses git user.signingkey) +.\.devcontainer\export-signing-key.ps1 + +# or pass a key explicitly +.\.devcontainer\export-signing-key.ps1 +``` + The helper auto-selects `gpg2`/`gpg` based on where your key is visible, which avoids host setups where the two binaries use different keyrings. diff --git a/.devcontainer/export-signing-key.ps1 b/.devcontainer/export-signing-key.ps1 new file mode 100644 index 0000000000..c9c3f4cd42 --- /dev/null +++ b/.devcontainer/export-signing-key.ps1 @@ -0,0 +1,118 @@ +#!/usr/bin/env pwsh +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# Export your GPG public key to .git/signing.pub so the devcontainer can auto-import it. +# Usage: +# .\.devcontainer\export-signing-key.ps1 +# .\.devcontainer\export-signing-key.ps1 + +param( + [Parameter(Position = 0)] + [string]$KeyId +) + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$repoRoot = Resolve-Path (Join-Path $scriptDir '..') +$outputFile = Join-Path $repoRoot '.git/signing.pub' + +if (-not $KeyId) { + $KeyId = (git config --global user.signingkey 2>$null).Trim() +} + +if (-not $KeyId) { + Write-Error 'No key ID provided and git user.signingkey is not set.' + Write-Host 'Set it with: git config --global user.signingkey ' + Write-Host 'Or run: .\.devcontainer\export-signing-key.ps1 ' + exit 1 +} + +$availableBins = @() +foreach ($candidate in @('gpg2', 'gpg')) { + if (Get-Command $candidate -ErrorAction SilentlyContinue) { + $availableBins += $candidate + } +} + +if ($availableBins.Count -eq 0) { + Write-Error 'Neither gpg nor gpg2 is available on PATH.' + exit 1 +} + +function Test-HasSecretKey { + param( + [string]$Bin, + [string]$Key + ) + + $lines = & $Bin --list-secret-keys --with-colons $Key 2>$null + return ($lines | Select-String '^sec' -Quiet) +} + +function Invoke-TryExport { + param( + [string]$Bin, + [string]$Key, + [string]$File + ) + + $content = & $Bin --armor --export $Key 2>$null + if ($LASTEXITCODE -ne 0) { + return $false + } + + if ([string]::IsNullOrWhiteSpace(($content -join ""))) { + return $false + } + + [System.IO.File]::WriteAllLines($File, $content, [System.Text.Encoding]::ASCII) + return ((Test-Path $File) -and ((Get-Item $File).Length -gt 0)) +} + +$selectedBin = $null +foreach ($bin in $availableBins) { + if (Test-HasSecretKey -Bin $bin -Key $KeyId) { + $selectedBin = $bin + break + } +} + +if (-not $selectedBin) { + $selectedBin = $availableBins[0] +} + +if (Test-Path $outputFile) { + Remove-Item $outputFile -Force +} + +$ok = Invoke-TryExport -Bin $selectedBin -Key $KeyId -File $outputFile +if (-not $ok) { + foreach ($bin in $availableBins) { + if ($bin -eq $selectedBin) { + continue + } + + $ok = Invoke-TryExport -Bin $bin -Key $KeyId -File $outputFile + if ($ok) { + $selectedBin = $bin + break + } + } +} + +if (-not $ok) { + if (Test-Path $outputFile) { + Remove-Item $outputFile -Force + } + + Write-Error "Failed to export public key for $KeyId." + Write-Host "Tried binaries: $($availableBins -join ' ')" + Write-Host 'Check key visibility with:' + Write-Host ' gpg --list-secret-keys --keyid-format=long' + Write-Host ' gpg2 --list-secret-keys --keyid-format=long' + exit 1 +} + +Write-Host "Exported public key $KeyId to $outputFile" +Write-Host "Using: $selectedBin" +Write-Host 'Rebuild/start the devcontainer to auto-import it.'