CI submits files to a small relay; a Windows agent runs signtool with your certificate and returns signed artifacts—without putting the signing key on the CI runner.
Note
Ahoy, traveler! 👋 This project has been "vibe-coded", meaning that the vast majority of the code has been written with the assistance of AI coding agents. I use my own work in production and value stability and security. Bear in mind, though, that the code you browse might not be an accurate reflection of my personal "style" or taste. The primary goal was to make a useful product, quickly, rather than focus on the development process itself. With that out of the way, if you find it useful, feel free to get inspired by it 😁
SignRelay is three parts: an ASP.NET Core relay (SignRelay.Server) that stores jobs and streams progress (Server-Sent Events), a Windows agent (SignRelay.Agent) that leases work and signs with the Windows SDK’s signtool, and a CLI (SignRelay.Cli) for pipelines to submit files and wait for signed outputs.
Operational detail—Docker, reverse proxies and SSE timeouts, MinVer, and NUKE targets—is in docs/DEPLOYMENT.md. Windows agent install: docs/AGENT-SETUP.md. Pipeline / CI consumer integration (Actions, MSBuild, AppVeyor, agent instructions): docs/CI-INTEGRATION.md.
- Bearer-token auth with separate CI and agent roles.
- Job lifecycle with SQLite metadata and blob storage under a configurable data directory.
- SSE endpoint for CI to wait on signing completion (
GET /api/v1/jobs/{id}/events). - Agent signing execution modes (
Auto,SameProcess,InteractiveUser) for console vs Windows Service and interactive certificate/smart-card UI. - Agent self-install verbs (
install/uninstall/status) with machine config under%ProgramData%, Event Log + rolling file logs, and self-contained win-x64 release zips. - CLI
signrelay submitwith--tokenorSIGN_RELAY_CI_TOKEN, optional--outputor--in-place, configurable--timeout, and--dry-run. - GitHub Actions composite (
action.yml/nefarius/SignRelay) and MSBuild package (Nefarius.Tools.SignRelay.MSBuild) for consumer pipelines. - Optional Docker or Podman image build for the server (see deployment doc).
- The signing agent targets Windows (certificate store,
signtool, session behavior). Other platforms are not supported for the agent. - Signing assumes a Microsoft-style
signtoolworkflow; other toolchains are out of scope. - Interactive signing relies on an appropriate logged-on session where applicable; multi-session/RDP edge cases are documented in
docs/DEPLOYMENT.md. - A reverse proxy in front of the relay must allow long-lived reads for the SSE stream (see deployment doc).
- Container image builds (Docker or Podman) do not copy
.git; image version usesMINVERVERSIONOVERRIDE(NUKEDockerServersets this). Seedocs/DEPLOYMENT.md.
| Component | Supported |
|---|---|
| SDK (build) | .NET SDK 10.x, minimum 10.0.100 per global.json (rollForward: latestFeature) |
| Relay server | Linux x64 for container/VPS-style deployment (default CI is ubuntu-latest; server is ASP.NET Core + SQLite) |
| Agent | Windows 10/11, x64 (primary); uses Windows SDK signtool (see agent options in deployment doc) |
| CLI | .NET 10–compatible runtime (same SDK builds the tool; install as global tool from packaged NuGet per deployment doc) |
| Git | 2.40+ recommended (tags use v prefix for MinVer, e.g. v1.2.3) |
-
Clone the repository.
-
Restore and build:
dotnet restore SignRelay.sln dotnet build SignRelay.sln -c Release
-
Or run the NUKE Publish pipeline (artifacts under
artifacts/, gitignored):chmod +x ./build.sh ./build.sh Publish
On Windows:
.\build.ps1 Publish
See docs/DEPLOYMENT.md for target names (PackContracts, PackCli, PackMsBuild, PublishServer, PublishAgent, DockerServer, etc.).
Server (production image): pin a release tag, e.g. nefarius.azurecr.io/signrelay:1.0.0 — see docker-compose.prod.yml (that file may track :latest for convenience; prefer a version tag in production). Set at least:
SignRelay__CiToken— bearer token for CI / CLI (≥ 32 characters).SignRelay__AgentToken— bearer token for the agent (≥ 32 characters).- Persist
SignRelay__StoragePath(compose uses/data).
Local Docker/Podman for development only: docker/compose.yml (ASPNETCORE_ENVIRONMENT=Development — not for production).
Agent (Windows): download SignRelay.Agent-<version>-win-x64.zip from Releases, extract, then from an elevated console:
.\SignRelay.Agent.exe install --relay-url https://relay.example.com --token "<agent-token>" --subject-name "Nefarius Software Solutions e.U." --start
.\SignRelay.Agent.exe statusFull walkthrough: docs/AGENT-SETUP.md.
CLI / CI pipelines:
dotnet tool install --global Nefarius.Tools.SignRelay
signrelay submit --server https://relay.example.com --token "$SIGN_RELAY_CI_TOKEN" --output ./signed ./artifacts/MyApp.exeUse SIGN_RELAY_CI_TOKEN matching SignRelay__CiToken on the server. Full consumer integration (GitHub Actions, MSBuild, AppVeyor, constraints for AI agents): docs/CI-INTEGRATION.md.
TLS, proxy timeouts, retention, and ACR tags: docs/DEPLOYMENT.md.
- .NET SDK 10.x — pinned in
global.json; install .NET 10 SDK or a newer 10.x patch. - NUKE — use repo bootstrappers
build.sh/build.ps1; a globalnuketool is not required. - Docker or Podman — optional, on
PATH, forDockerServer/ image builds. The engine is auto-detected (dockerfirst, thenpodman); override with--ContainerEngine podman.
Versioning uses MinVer with tag prefix v. The build project under build/ is excluded from MinVer.
- Use the issue tracker for defects and concrete improvements to this repository.
- Operational or environment-specific setup (proxies, certificates, org policy) is your responsibility; read
docs/DEPLOYMENT.mdfirst. - Issues with incomplete reproduction details or requests outside documented scope may be closed.
- Terminate TLS in front of the relay in production; do not send bearer tokens over untrusted plaintext networks.
- Rotate CI and agent tokens independently; they represent different principals.
- Restrict network access to the relay where possible.
See the Security checklist in docs/DEPLOYMENT.md.
This project is licensed under the MIT License — see LICENSE.
Copyright (c) 2026 Benjamin Höglinger-Stelzer.
Windows, .NET, and other product names are trademarks of their respective owners. References here are for identification only.
- Agent install walkthrough:
docs/AGENT-SETUP.md - CI / pipeline integration:
docs/CI-INTEGRATION.md - Deployment and build reference:
docs/DEPLOYMENT.md - Distributable agent skill:
skills/signrelay-ci/ - Versioning: MinVer
- HTTP API: FastEndpoints
- Optional
signtooldiscovery: wdkwhere, Nefarius.Tools.WDKWhere - Documentation style baseline:
.cursor/rules/readme-style.mdc,AGENTS.md
