Просмотр исходного кода

obfuscate windows builds to avoid defender quarantine

Mike 2 лет назад
Родитель
Сommit
2d0f7a2716
4 измененных файлов с 162 добавлено и 29 удалено
  1. 63 23
      .goreleaser.yaml
  2. 5 0
      Dockerfile.goreleaser
  3. 18 6
      Makefile
  4. 76 0
      docs/RELEASE.md

+ 63 - 23
.goreleaser.yaml

@@ -5,46 +5,86 @@ before:
     - go mod tidy
 
 builds:
-  - binary: retro_aim_server
+  - id: linux
+    binary: retro_aim_server
     goos:
-      - darwin
       - linux
-      - windows
     goarch:
       - amd64
-      - arm64
     main: ./cmd/server
     ignore:
       - goos: linux
         goarch: arm64
-      - goos: windows
-        goarch: arm64
+    env:
+      - CGO_ENABLED=1
+      - CC=x86_64-linux-gnu-gcc
+  - id: macos
+    binary: retro_aim_server
+    goos:
+      - darwin
+    goarch:
+      - amd64
+      - arm64
+    main: ./cmd/server
     env:
       - CGO_ENABLED=1
       - >-
-        {{- if eq .Os "darwin" }}
-          {{- if eq .Arch "amd64"}}CC=o64-clang{{- end }}
-          {{- if eq .Arch "arm64"}}CC=oa64-clang{{- end }}
-        {{- end }}
-        {{- if eq .Os "linux" }}CC=x86_64-linux-gnu-gcc{{- end }}
-        {{- if eq .Os "windows" }}CC=x86_64-w64-mingw32-gcc{{- end }}
+        {{- if eq .Arch "amd64"}}CC=o64-clang{{- end }}
+        {{- if eq .Arch "arm64"}}CC=oa64-clang{{- end }}
+  - id: windows
+    binary: retro_aim_server
+    goos:
+      - windows
+    goarch:
+      - amd64
+    main: ./cmd/server
+    env:
+      - CGO_ENABLED=1
+      - CC=x86_64-w64-mingw32-gcc
+    gobinary: /root/go/bin/garble
 
 archives:
-  - format: tar.gz
-    format_overrides:
-      - goos: windows
-        format: zip
+  - id: linux
+    builds:
+      - linux
+    format: tar.gz
+    wrap_in_directory: true
+    files:
+      - LICENSE
+      - src: config/settings.env
+        strip_parent: true
+      - src: scripts/run.sh
+        strip_parent: true
+    name_template: >-
+      {{ .Binary }}.{{ .Version }}.{{ .Os }}.
+      {{- if eq .Arch "amd64" }}x86_64
+      {{- else }}{{ .Arch }}{{ end }}
+  - id: macos
+    builds:
+      - macos
+    format: zip
+    wrap_in_directory: true
+    files:
+      - LICENSE
+      - src: config/settings.env
+        strip_parent: true
+      - src: scripts/run.sh
+        strip_parent: true
+    name_template: >-
+      {{ .Binary }}.{{ .Version }}.macos.
+      {{- if eq .Arch "amd64" }}intel_x86_64{{ else }}apple_silicon{{ end }}
+  - id: windows
+    builds:
+      - windows
+    format: zip
     wrap_in_directory: true
     files:
       - LICENSE
-      - src: config/settings.{{- if eq .Os "windows" }}bat{{ else }}env{{ end }}
+      - src: config/settings.bat
         strip_parent: true
-      - src: scripts/run.{{- if eq .Os "windows" }}cmd{{ else }}sh{{ end }}
+      - src: scripts/run.cmd
         strip_parent: true
     name_template: >-
-      {{ .Binary }}.{{ .Version }}.
-      {{- if eq .Os "darwin"}}macos
-      {{- else }}{{ .Os }}{{ end }}.
-      {{- if eq .Os "darwin"}}{{- if eq .Arch "amd64" }}intel_x86_64{{ else }}apple_silicon{{ end }}
-      {{- else if eq .Arch "amd64" }}x86_64
+      {{ .Binary }}.{{ .Version }}.{{ .Os }}.
+      {{- if eq .Arch "amd64" }}x86_64
       {{- else }}{{ .Arch }}{{ end }}

+ 5 - 0
Dockerfile.goreleaser

@@ -0,0 +1,5 @@
+ARG GO_RELEASER_CROSS_VERSION
+FROM goreleaser/goreleaser-cross:$GO_RELEASER_CROSS_VERSION
+
+ARG GARBLE_VERSION
+RUN go install mvdan.cc/garble@$GARBLE_VERSION

+ 18 - 6
Makefile

@@ -1,11 +1,14 @@
-GO_RELEASER_VERSION := v1.21.5
+GO_RELEASER_CROSS_VERSION := v1.22.1
+DOCKER_IMAGE_TAG := goreleaser-cross-garble:${GO_RELEASER_CROSS_VERSION}
+GARBLE_VERSION := v0.12.1
+
 DOCKER_RUN := @docker run \
+	--env CGO_ENABLED=1 \
+	--env GITHUB_TOKEN=$(GITHUB_TOKEN) \
 	--rm \
-	-e CGO_ENABLED=1 \
-	-e GITHUB_TOKEN=$(GITHUB_TOKEN) \
-	-v `pwd`:/go/src/retro-aim-server \
-	-w /go/src/retro-aim-server \
-	ghcr.io/goreleaser/goreleaser-cross:$(GO_RELEASER_VERSION)
+	--volume `pwd`:/go/src/retro-aim-server \
+	--workdir /go/src/retro-aim-server \
+	$(DOCKER_IMAGE_TAG)
 
 .PHONY: release
 release:
@@ -14,3 +17,12 @@ release:
 .PHONY: release-dry-run
 release-dry-run:
 	$(DOCKER_RUN) --clean --skip=validate --skip=publish
+
+.PHONY: goreleaser-docker
+goreleaser-docker:
+	@docker build \
+		--build-arg GARBLE_VERSION=$(GARBLE_VERSION) \
+		--build-arg GO_RELEASER_CROSS_VERSION=$(GO_RELEASER_CROSS_VERSION) \
+		--file Dockerfile.goreleaser \
+		--tag $(DOCKER_IMAGE_TAG) \
+		.

+ 76 - 0
docs/RELEASE.md

@@ -0,0 +1,76 @@
+# Releasing
+
+This document explains how the Retro AIM Server release process works.
+
+## Overview
+
+Retro AIM Server is built and released to Github using [GoReleaser](https://goreleaser.com/). The release process, which
+runs from a local computer (and not a CI/CD process) creates pre-built binaries for several platforms (Windows, MacOS,
+Linux).
+
+GoReleaser runs in a Docker container for two important reasons:
+
+- Docker provides a hermetic environment that prevents build contamination from the host environment.
+- The Docker image [goreleaser-cross](https://github.com/goreleaser/goreleaser-cross) consolidates all the libraries
+  needed for cross-compilation in one place.
+    - Given that the application uses cgo, it's much easier to use a pre-built container to build the sqlite library
+      than to manually set up a C compiler on Mac/Windows/Linux etc.
+
+### Code Signing Policy
+
+Given the cost and complexity of code signing, this project only distributes unsigned binaries. This means that
+MacOS distrusts Retro AIM Server by default and quarantines the application when you open it.
+> If you don't want to bypass this security mechanism, you can [build the project yourself](./building) instead.
+
+### Windows Build Obfuscation
+
+Due to cost and complexity, none of the release artifacts are signed. One consequence of this is that Windows Defender
+falsely detects [the `.exe` as a virus](https://go.dev/doc/faq#virus) and auto-quarantines the file upon execution.
+
+We get around this by obfuscating the go binary at built time using [garble](https://github.com/burrowers/garble). In
+order to accomplish this, the project wraps GoReleaser and garble in a custom Dockerfile `Dockerfile.goreleaser`.
+
+The GoRelease-garble image must be built locally before running the release process.
+
+## Release Procedure
+
+The following is the procedure that builds Retro AIM Server and uploads the build artifacts to a Github release.
+
+1. **Build Custom Docker Image**
+
+   Build the custom GoReleaser Docker image. Ensure that the latest version is set under `GO_RELEASER_CROSS_VERSION` in
+   the project Makefile.
+
+    ```sh
+    make goreleaser-docker
+    ```
+
+2. **Export Github Personal Access Token (PAT)**
+
+   Export a Github Personal Access Token that has `write:packages` permissions for the Retro AIM Server repo.
+
+    ```sh
+    export GITHUB_TOKEN=...
+    ```
+
+3. **Tag The Build**
+
+   Tag the build using [semantic versioning](https://semver.org/).
+    ```shell
+    git tag v0.1.0
+    git push --tags
+    ```
+
+4. **Dry-Run Release**
+
+   Execute a dry-run build to make sure all the moving parts work together. Fix any problems that crop up before
+   continuing.
+
+    ```shell
+   make release-dry-run
+    ```
+
+5. **Release It!**
+
+   Now run the release process. Once its complete, a new [release](https://github.com/mk6i/retro-aim-server/releases)
+   should appear in Github with download artifacts attached.