From 882d5332b43143dd5400f69320bfe6beb860379f Mon Sep 17 00:00:00 2001 From: Justin Paul Date: Fri, 8 May 2026 08:17:05 -0400 Subject: [PATCH] Add dev-launch.ps1 to start service + GUI for visual smoke testing Stands up an isolated data root, seeds a single sample endpoint, opens the service in its own window, then launches the GUI with the matching WEBHOOKSERVER_DATA environment variable. Refuses to run from a non-elevated shell since the admin pipe is ACL'd to SYSTEM and Administrators only. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/dev-launch.ps1 | 83 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 scripts/dev-launch.ps1 diff --git a/scripts/dev-launch.ps1 b/scripts/dev-launch.ps1 new file mode 100644 index 0000000..8330b20 --- /dev/null +++ b/scripts/dev-launch.ps1 @@ -0,0 +1,83 @@ +<# +.SYNOPSIS + Dev launcher: starts the service in one window and the GUI in another, both + pointing at an isolated data root so production %ProgramData% is not touched. + +.DESCRIPTION + MUST be run from an elevated PowerShell — the admin pipe is ACL'd to SYSTEM + and the Administrators group, and a non-elevated process cannot connect. +#> +[CmdletBinding()] +param( + [string]$DataRoot = (Join-Path $env:TEMP 'webhook-dev'), + [int]$HttpPort = 18080 +) + +$ErrorActionPreference = 'Stop' +$root = Split-Path -Parent $PSScriptRoot +$servicePath = Join-Path $root 'publish\service\WebhookServer.Service.exe' +$guiPath = Join-Path $root 'publish\gui\WebhookServer.Gui.exe' + +if (-not (Test-Path $servicePath)) { throw "Service not built. Run: dotnet publish src/WebhookServer.Service -c Release -o publish/service" } +if (-not (Test-Path $guiPath)) { throw "GUI not built. Run: dotnet publish src/WebhookServer.Gui -c Release -o publish/gui" } + +# Verify the current shell is elevated. +$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) +if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { + throw 'This script must be run from an elevated PowerShell so the GUI can connect to the SYSTEM/Admins-only admin pipe.' +} + +New-Item -ItemType Directory -Path $DataRoot -Force | Out-Null +New-Item -ItemType Directory -Path (Join-Path $DataRoot 'logs') -Force | Out-Null + +$cfgPath = Join-Path $DataRoot 'config.json' +if (-not (Test-Path $cfgPath)) { + $cfg = @" +{ + "httpPort": $HttpPort, + "trustedProxies": [], + "logRetentionDays": 7, + "endpoints": [ + { + "id": "11111111-1111-1111-1111-111111111111", + "slug": "ping", + "description": "Trivial sync hook", + "enabled": true, + "allowedClients": [], + "authMode": "none", + "executorType": "windowsPowerShell", + "inlineCommand": "Write-Output 'pong'", + "executableArgs": [], + "dataPassing": { "stdinJson": false, "envVars": false, "argTemplate": false }, + "responseMode": "sync", + "timeoutSeconds": 30, + "failOnNonZeroExit": true, + "serialize": false + } + ] +} +"@ + Set-Content -Path $cfgPath -Value $cfg -Encoding utf8 +} + +Write-Host "Data root : $DataRoot" +Write-Host "Config : $cfgPath" +Write-Host "Service exe: $servicePath" +Write-Host "GUI exe : $guiPath" +Write-Host "" + +$serviceArgs = @( + '-NoExit', '-NoProfile', '-Command', + "`$env:WEBHOOKSERVER_DATA = '$DataRoot'; & '$servicePath'" +) +Start-Process powershell -ArgumentList $serviceArgs -WindowStyle Normal + +Start-Sleep -Seconds 2 + +# GUI inherits this shell's environment automatically. +$env:WEBHOOKSERVER_DATA = $DataRoot +Start-Process -FilePath $guiPath + +Write-Host "Service window opened; GUI launched." +Write-Host "Hit http://localhost:$HttpPort/healthz to confirm Kestrel is up." +Write-Host "Logs: $(Join-Path $DataRoot 'logs')"