From 33f489dfb01f236d41d83b81f80cf9e3454e974a Mon Sep 17 00:00:00 2001 From: jamesread Date: Tue, 21 Jul 2026 15:55:56 +0100 Subject: [PATCH] chore: Windows build split --- .github/workflows/build-and-release.yml | 4 +- .goreleaser.yml | 61 ++++++++++++++++++------- docs/modules/dev/pages/signing.adoc | 14 +++--- var/windows/signpath-publish-signed.sh | 7 ++- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index d465ebd..29071c7 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -207,7 +207,7 @@ jobs: fi done if [[ "${missing}" -ne 0 ]]; then - echo "Windows signing is required before a draft release can be published. Configure SignPath secrets/vars (see docs/modules/dev/pages/signing.adoc)." >&2 + echo "SignPath secrets/vars are required to upload signed Windows assets. Configure them (see docs/modules/dev/pages/signing.adoc)." >&2 exit 1 fi @@ -238,7 +238,7 @@ jobs: skip-decompress: true output-artifact-directory: signed-windows-msi - - name: Publish signed Windows assets and undraft release + - name: Upload signed Windows assets env: GH_TOKEN: ${{ secrets.CONTAINER_TOKEN }} GITHUB_TOKEN: ${{ secrets.CONTAINER_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml index b56a7bd..e9939d6 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -6,6 +6,7 @@ before: - make windows-resources VERSION={{ .Version }} builds: + # id defaults to project_name (OliveTin) — required for notarize.macos defaults. - skip: '{{ isEnvSet "GORELEASER_SKIP_BUILD" }}' env: - CGO_ENABLED=0 @@ -14,7 +15,6 @@ builds: dir: service goos: - linux - - windows - darwin - freebsd @@ -33,19 +33,31 @@ builds: - goos: darwin goarch: arm # Mac does not work on [32bit] arm - - goos: windows - goarch: arm - - - goos: windows # Does anyone use Windows on arm64? - goarch: arm64 + ldflags: + - -s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{ .CommitDate }} + # Built and archived for SignPath, but excluded from the GitHub release upload. + - id: windows + skip: '{{ isEnvSet "GORELEASER_SKIP_BUILD" }}' + env: + - CGO_ENABLED=0 + binary: OliveTin + main: . + dir: service + goos: + - windows + goarch: + - amd64 ldflags: - -s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{ .CommitDate }} checksum: name_template: 'checksums.txt' - extra_files: - - glob: ./dist/OliveTin-windows-amd64.msi + # Exclude the windows archive; signed zip/MSI checksums are added after SignPath. + ids: + - default + - openrc + snapshot: version_template: "{{ .Branch }}-{{ .ShortCommit }}" changelog: @@ -73,7 +85,26 @@ changelog: - '^Merge branch' archives: - - formats: tar.gz + - id: default + ids: + - OliveTin + formats: tar.gz + files: + - config.yaml + - LICENSE + - README.md + - src: Dockerfile.singlearch + dst: Dockerfile + - examples/backupScript.sh + - webui + - var + name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}" + wrap_in_directory: true + + - id: windows + ids: + - windows + formats: zip files: - config.yaml - LICENSE @@ -85,9 +116,6 @@ archives: - var name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}" wrap_in_directory: true - format_overrides: - - goos: windows - formats: zip # dockers_v2: single multi-platform build with buildx; keeps default provenance + SBOM. # Replaces legacy dockers + docker_manifests (avoids "is a manifest list" when attestations are on). @@ -199,10 +227,11 @@ notarize: timeout: 30m release: - # Stay draft until the sign-windows job replaces unsigned Windows assets and undrafts. - draft: true - extra_files: - - glob: ./dist/OliveTin-windows-amd64.msi + # Publish immediately without Windows assets; sign-windows uploads signed zip/MSI later. + draft: false + ids: + - default + - openrc footer: | ## Container images (from GitHub) diff --git a/docs/modules/dev/pages/signing.adoc b/docs/modules/dev/pages/signing.adoc index 500db94..478bc8b 100644 --- a/docs/modules/dev/pages/signing.adoc +++ b/docs/modules/dev/pages/signing.adoc @@ -3,7 +3,7 @@ OliveTin signs release binaries on two platforms: * **macOS** — Developer ID + notarization via [quill](https://github.com/anchore/quill) inside GoReleaser (optional only when `MACOS_SIGN_P12` is unset). -* **Windows** — Authenticode via [SignPath Foundation](https://signpath.org/) in a separate GitHub Actions job (required before a draft release is published). +* **Windows** — Authenticode via [SignPath Foundation](https://signpath.org/) in a separate GitHub Actions job (signed zip/MSI are uploaded after the release is published). ## macOS release signing @@ -117,14 +117,14 @@ A signed and notarized binary should report `accepted` with `source=Notarized De Windows Authenticode signing uses [SignPath Foundation](https://signpath.org/) (free for qualifying open-source projects). It does **not** use GoReleaser Pro. -GoReleaser creates a **draft** GitHub release with unsigned Windows assets. A separate `sign-windows` job submits those assets to SignPath, replaces them on the draft (including updated `checksums.txt`), then publishes the release. +GoReleaser publishes a GitHub release **without** Windows zip/MSI assets. A separate `sign-windows` job submits the unsigned Windows files (as workflow artifacts) to SignPath, then uploads the signed zip/MSI and updates `checksums.txt` on the already-published release. Signed artifacts: * `OliveTin.exe` inside `OliveTin-windows-amd64.zip` * nested `OliveTin.exe` and the `OliveTin-windows-amd64.msi` installer (deep signing) -Signing is **required** to publish. If SignPath secrets/vars are missing, `sign-windows` fails and the draft stays unpublished. +If SignPath secrets/vars are missing or signing fails, the release still publishes; Windows assets are simply missing until a successful `sign-windows` run. Install URLs for the Windows zip may 404 until signing finishes. ### Prerequisites @@ -168,9 +168,9 @@ In **Settings → Secrets and variables → Actions**: On a new semantic-release from `main`: -1. GoReleaser publishes container images and creates a **draft** GitHub release (including unsigned Windows zip/MSI). -2. The build job uploads those Windows files as GitHub Actions artifacts. -3. The `sign-windows` job submits each artifact to SignPath, waits for completion, then runs `var/windows/signpath-publish-signed.sh` to clobber-upload signed files, refresh `checksums.txt`, and undraft the release. +1. GoReleaser publishes container images and a GitHub release **without** Windows zip/MSI assets (those are built locally for SignPath only). +2. The build job uploads the unsigned Windows files as GitHub Actions artifacts. +3. The `sign-windows` job submits each artifact to SignPath, waits for completion, then runs `var/windows/signpath-publish-signed.sh` to upload the signed files and refresh `checksums.txt`. All jobs in this chain use GitHub-hosted runners (required by SignPath for OSS projects). @@ -188,7 +188,7 @@ signtool verify /pa OliveTin-windows-amd64.msi ### Configuration reference -- Draft release: `release.draft: true` in link:https://github.com/OliveTin/OliveTin/blob/main/.goreleaser.yml[`.goreleaser.yml`] +- Release publish (no Windows assets initially): `release.draft: false` and `release.ids` in link:https://github.com/OliveTin/OliveTin/blob/main/.goreleaser.yml[`.goreleaser.yml`] - CI job: `sign-windows` in link:https://github.com/OliveTin/OliveTin/blob/main/.github/workflows/build-and-release.yml[`.github/workflows/build-and-release.yml`] - Publish helper: link:https://github.com/OliveTin/OliveTin/blob/main/var/windows/signpath-publish-signed.sh[`var/windows/signpath-publish-signed.sh`] - SignPath artifact configs (reference only): link:https://github.com/OliveTin/OliveTin/blob/main/docs/modules/dev/signpath/windows-zip.xml[`signpath/windows-zip.xml`], link:https://github.com/OliveTin/OliveTin/blob/main/docs/modules/dev/signpath/windows-msi.xml[`signpath/windows-msi.xml`] diff --git a/var/windows/signpath-publish-signed.sh b/var/windows/signpath-publish-signed.sh index 941e592..3da7d96 100755 --- a/var/windows/signpath-publish-signed.sh +++ b/var/windows/signpath-publish-signed.sh @@ -72,7 +72,8 @@ update_checksum() { update_checksum "${ZIP_NAME}" update_checksum "${MSI_NAME}" -# Replace binaries first so a failed checksums upload leaves the draft recoverable. +# Upload binaries first so a failed checksums upload can restore the previous file. +# --clobber overwrites same-named assets (needed if the sign job is re-run). gh release upload "${TAG}" \ "${DIST_DIR}/${ZIP_NAME}" \ "${DIST_DIR}/${MSI_NAME}" \ @@ -87,6 +88,4 @@ if ! gh release upload "${TAG}" "${checksums_path}" --clobber; then exit 1 fi -gh release edit "${TAG}" --draft=false - -echo "Published signed ${ZIP_NAME} and ${MSI_NAME} on release ${TAG}" +echo "Uploaded signed ${ZIP_NAME} and ${MSI_NAME} to release ${TAG}"