diff --git a/.github/workflows/beta-release.yml b/.github/workflows/beta-release.yml index 3927395..dcdd4d3 100644 --- a/.github/workflows/beta-release.yml +++ b/.github/workflows/beta-release.yml @@ -69,6 +69,32 @@ jobs: echo "Production version: ${PROD_VERSION}" echo "Beta tag: ${BETA_VERSION}" + - name: Generate Windows resource files + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + go install github.com/tc-hib/go-winres@latest + + # Parse version components (e.g., "0.5.3-beta.1" → "0.5.3.0") + CLEAN_VER=$(echo "$VERSION" | sed 's/-.*//') + MAJOR=$(echo "$CLEAN_VER" | cut -d. -f1) + MINOR=$(echo "$CLEAN_VER" | cut -d. -f2) + PATCH=$(echo "$CLEAN_VER" | cut -d. -f3) + FILE_VER="${MAJOR:-0}.${MINOR:-0}.${PATCH:-0}.0" + + # Update version in winres.json + cd cmd/routatic-proxy + sed -i.bak "s/\"file_version\": \"0.0.0.0\"/\"file_version\": \"${FILE_VER}\"/" winres/winres.json + sed -i.bak "s/\"product_version\": \"0.0.0.0\"/\"product_version\": \"${FILE_VER}\"/" winres/winres.json + sed -i.bak "s/\"FileVersion\": \"0.0.0.0\"/\"FileVersion\": \"${VERSION}\"/" winres/winres.json + sed -i.bak "s/\"ProductVersion\": \"0.0.0.0\"/\"ProductVersion\": \"${VERSION}\"/" winres/winres.json + rm -f winres/winres.json.bak + + # Generate .syso files for both Windows architectures + go-winres make --arch amd64 --out rsrc_windows_amd64.syso + go-winres make --arch arm64 --out rsrc_windows_arm64.syso + cd ../.. + - name: Build cross-platform binaries env: VERSION: ${{ steps.version.outputs.version }} @@ -99,6 +125,37 @@ jobs: echo "Built binaries:" ls -lh dist/ + - name: Package Windows binaries for signing + if: ${{ secrets.SIGNPATH_API_TOKEN != '' }} + run: | + mkdir -p signing + cp dist/routatic-proxy_windows-amd64.exe signing/ + cp dist/routatic-proxy_windows-arm64.exe signing/ + cd signing && zip ../windows-binaries.zip *.exe + + - name: Sign Windows binaries (SignPath) + if: ${{ secrets.SIGNPATH_API_TOKEN != '' }} + uses: signpath/github-action-submit-signing-request@ced31329c0317e779dad2eec2a7c3bb46ea1343e # v1 + with: + api-token: ${{ secrets.SIGNPATH_API_TOKEN }} + organization-id: '5c4d4e48-c428-4e10-ab07-8db7f46cbec9' + project-slug: 'routatic-proxy' + signing-policy-slug: 'release-signing' + artifact-configuration-slug: 'windows-exe' + github-artifact-id: 'windows-binaries' + input-artifact-path: 'windows-binaries.zip' + output-artifact-path: 'windows-binaries-signed.zip' + wait-for-completion: true + wait-for-completion-timeout-in-seconds: 300 + + - name: Replace with signed Windows binaries + if: ${{ secrets.SIGNPATH_API_TOKEN != '' }} + run: | + unzip -o windows-binaries-signed.zip -d signed/ + cp signed/routatic-proxy_windows-amd64.exe dist/routatic-proxy_windows-amd64.exe + cp signed/routatic-proxy_windows-arm64.exe dist/routatic-proxy_windows-arm64.exe + rm -rf signing signed windows-binaries.zip windows-binaries-signed.zip + - name: Generate checksums run: | cd dist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 50732e4..575b4c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -68,6 +68,31 @@ jobs: echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" echo "Releasing as $TAG" + - name: Generate Windows resource files + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + go install github.com/tc-hib/go-winres@latest + + # Parse version components (e.g., "0.5.3" → "0.5.3.0") + MAJOR=$(echo "$VERSION" | cut -d. -f1) + MINOR=$(echo "$VERSION" | cut -d. -f2) + PATCH=$(echo "$VERSION" | cut -d. -f3) + FILE_VER="${MAJOR:-0}.${MINOR:-0}.${PATCH:-0}.0" + + # Update version in winres.json + cd cmd/routatic-proxy + sed -i.bak "s/\"file_version\": \"0.0.0.0\"/\"file_version\": \"${FILE_VER}\"/" winres/winres.json + sed -i.bak "s/\"product_version\": \"0.0.0.0\"/\"product_version\": \"${FILE_VER}\"/" winres/winres.json + sed -i.bak "s/\"FileVersion\": \"0.0.0.0\"/\"FileVersion\": \"${VERSION}\"/" winres/winres.json + sed -i.bak "s/\"ProductVersion\": \"0.0.0.0\"/\"ProductVersion\": \"${VERSION}\"/" winres/winres.json + rm -f winres/winres.json.bak + + # Generate .syso files for both Windows architectures + go-winres make --arch amd64 --out rsrc_windows_amd64.syso + go-winres make --arch arm64 --out rsrc_windows_arm64.syso + cd ../.. + - name: Build cross-platform binaries env: VERSION: ${{ steps.version.outputs.version }} @@ -98,6 +123,37 @@ jobs: echo "Built binaries:" ls -lh dist/ + - name: Package Windows binaries for signing + if: ${{ secrets.SIGNPATH_API_TOKEN != '' }} + run: | + mkdir -p signing + cp dist/routatic-proxy_windows-amd64.exe signing/ + cp dist/routatic-proxy_windows-arm64.exe signing/ + cd signing && zip ../windows-binaries.zip *.exe + + - name: Sign Windows binaries (SignPath) + if: ${{ secrets.SIGNPATH_API_TOKEN != '' }} + uses: signpath/github-action-submit-signing-request@ced31329c0317e779dad2eec2a7c3bb46ea1343e # v1 + with: + api-token: ${{ secrets.SIGNPATH_API_TOKEN }} + organization-id: '5c4d4e48-c428-4e10-ab07-8db7f46cbec9' + project-slug: 'routatic-proxy' + signing-policy-slug: 'release-signing' + artifact-configuration-slug: 'windows-exe' + github-artifact-id: 'windows-binaries' + input-artifact-path: 'windows-binaries.zip' + output-artifact-path: 'windows-binaries-signed.zip' + wait-for-completion: true + wait-for-completion-timeout-in-seconds: 300 + + - name: Replace with signed Windows binaries + if: ${{ secrets.SIGNPATH_API_TOKEN != '' }} + run: | + unzip -o windows-binaries-signed.zip -d signed/ + cp signed/routatic-proxy_windows-amd64.exe dist/routatic-proxy_windows-amd64.exe + cp signed/routatic-proxy_windows-arm64.exe dist/routatic-proxy_windows-arm64.exe + rm -rf signing signed windows-binaries.zip windows-binaries-signed.zip + - name: Generate checksums run: | cd dist diff --git a/.gitignore b/.gitignore index 46662f1..1fb1d34 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ router.test .playwright-mcp .gstack/ node_modules/ + +# Generated Windows resource files (built by go-winres in CI) +*.syso diff --git a/cmd/routatic-proxy/winres/winres.json b/cmd/routatic-proxy/winres/winres.json new file mode 100644 index 0000000..94af95a --- /dev/null +++ b/cmd/routatic-proxy/winres/winres.json @@ -0,0 +1,47 @@ +{ + "RT_MANIFEST": { + "#1": { + "0409": { + "identity": { + "name": "Routatic.Proxy", + "version": "0.0.0.0" + }, + "description": "Routatic Proxy - AI Model Router", + "minimum-os": "win7", + "execution-level": "asInvoker", + "ui-access": false, + "auto-elevate": false, + "dpi-awareness": "system", + "disable-theming": false, + "disable-window-filtering": false, + "high-resolution-scrolling-aware": false, + "ultra-high-resolution-scrolling-aware": false, + "long-path-aware": true, + "gdi-scaling": false + } + } + }, + "RT_VERSION": { + "#1": { + "0000": { + "fixed": { + "file_version": "0.0.0.0", + "product_version": "0.0.0.0" + }, + "info": { + "0409": { + "Comments": "AI model routing proxy for Claude Code", + "CompanyName": "Routatic", + "FileDescription": "Routatic Proxy - AI Model Router", + "FileVersion": "0.0.0.0", + "InternalName": "routatic-proxy", + "LegalCopyright": "Copyright (c) 2024-2026 Routatic", + "OriginalFilename": "routatic-proxy.exe", + "ProductName": "Routatic Proxy", + "ProductVersion": "0.0.0.0" + } + } + } + } + } +} diff --git a/cmd/routatic-proxy/winres/winres.xml b/cmd/routatic-proxy/winres/winres.xml new file mode 100644 index 0000000..46718e2 --- /dev/null +++ b/cmd/routatic-proxy/winres/winres.xml @@ -0,0 +1,33 @@ + + + + Routatic Proxy - AI Model Router + + + + + + + + + + + + + + + + + + + + + + true + + +