From 85e2a6a3a583cfffdd4d661970cc99af5b87111d Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 26 Feb 2025 01:18:00 +0000 Subject: [PATCH 1/6] feat: include winres metadata in Windows binaries Adds information like product/file version, description, product name and copyright to compiled Windows binaries in dogfood and release builds. --- .github/workflows/ci.yaml | 48 ++++++++++++- .github/workflows/release.yaml | 28 ++++---- buildinfo/resources/.gitignore | 1 + buildinfo/resources/resources.go | 8 +++ cmd/coder/main.go | 1 + enterprise/cmd/coder/main.go | 1 + scripts/build_go.sh | 114 +++++++++++++++++++++++++++++-- 7 files changed, 181 insertions(+), 20 deletions(-) create mode 100644 buildinfo/resources/.gitignore create mode 100644 buildinfo/resources/resources.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bf1428df6cc3a..cfa73ec597d61 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1050,12 +1050,44 @@ jobs: - name: Setup Go uses: ./.github/actions/setup-go + # Necessary for signing Windows binaries. + - name: Setup Java + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 + with: + distribution: "zulu" + java-version: "11.0" + + - name: Install go-winres + run: go install github.com/tc-hib/go-winres@d743268d7ea168077ddd443c4240562d4f5e8c3e # v0.3.3 + - name: Install nfpm run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.35.1 - name: Install zstd run: sudo apt-get install -y zstd + - name: Setup Windows EV Signing Certificate + run: | + set -euo pipefail + touch /tmp/ev_cert.pem + chmod 600 /tmp/ev_cert.pem + echo "$EV_SIGNING_CERT" > /tmp/ev_cert.pem + wget https://github.com/ebourg/jsign/releases/download/6.0/jsign-6.0.jar -O /tmp/jsign-6.0.jar + env: + EV_SIGNING_CERT: ${{ secrets.EV_SIGNING_CERT }} + + # Setup GCloud for signing Windows binaries. + - name: Authenticate to Google Cloud + id: gcloud_auth + uses: google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935 # v2.1.8 + with: + workload_identity_provider: ${{ secrets.GCP_CODE_SIGNING_WORKLOAD_ID_PROVIDER }} + service_account: ${{ secrets.GCP_CODE_SIGNING_SERVICE_ACCOUNT }} + token_format: "access_token" + + - name: Setup GCloud SDK + uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4 + - name: Download dylibs uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: @@ -1082,6 +1114,18 @@ jobs: build/coder_linux_{amd64,arm64,armv7} \ build/coder_"$version"_windows_amd64.zip \ build/coder_"$version"_linux_amd64.{tar.gz,deb} + env: + # The Windows slim binary must be signed for Coder Desktop to accept + # it. The darwin executables don't need to be signed, but the dylibs + # do (see above). + CODER_SIGN_WINDOWS: "1" + CODER_WINDOWS_RESOURCES: "1" + EV_KEY: ${{ secrets.EV_KEY }} + EV_KEYSTORE: ${{ secrets.EV_KEYSTORE }} + EV_TSA_URL: ${{ secrets.EV_TSA_URL }} + EV_CERTIFICATE_PATH: /tmp/ev_cert.pem + GCLOUD_ACCESS_TOKEN: ${{ steps.gcloud_auth.outputs.access_token }} + JSIGN_PATH: /tmp/jsign-6.0.jar - name: Build Linux Docker images id: build-docker @@ -1183,10 +1227,10 @@ jobs: uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4 - name: Set up Flux CLI - uses: fluxcd/flux2/action@af67405ee43a6cd66e0b73f4b3802e8583f9d961 # v2.5.0 + uses: fluxcd/flux2/action@8d5f40dca5aa5d3c0fc3414457dda15a0ac92fa4 # v2.5.1 with: # Keep this and the github action up to date with the version of flux installed in dogfood cluster - version: "2.2.1" + version: "2.5.1" - name: Get Cluster Credentials uses: google-github-actions/get-gke-credentials@7a108e64ed8546fe38316b4086e91da13f4785e1 # v2.3.1 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 89b4e4e84a401..614b3542d5a80 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -223,21 +223,12 @@ jobs: distribution: "zulu" java-version: "11.0" + - name: Install go-winres + run: go install github.com/tc-hib/go-winres@d743268d7ea168077ddd443c4240562d4f5e8c3e # v0.3.3 + - name: Install nsis and zstd run: sudo apt-get install -y nsis zstd - - name: Download dylibs - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - with: - name: dylibs - path: ./build - - - name: Insert dylibs - run: | - mv ./build/*amd64.dylib ./site/out/bin/coder-vpn-darwin-amd64.dylib - mv ./build/*arm64.dylib ./site/out/bin/coder-vpn-darwin-arm64.dylib - mv ./build/*arm64.h ./site/out/bin/coder-vpn-darwin-dylib.h - - name: Install nfpm run: | set -euo pipefail @@ -294,6 +285,18 @@ jobs: - name: Setup GCloud SDK uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4 + - name: Download dylibs + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: dylibs + path: ./build + + - name: Insert dylibs + run: | + mv ./build/*amd64.dylib ./site/out/bin/coder-vpn-darwin-amd64.dylib + mv ./build/*arm64.dylib ./site/out/bin/coder-vpn-darwin-arm64.dylib + mv ./build/*arm64.h ./site/out/bin/coder-vpn-darwin-dylib.h + - name: Build binaries run: | set -euo pipefail @@ -310,6 +313,7 @@ jobs: env: CODER_SIGN_WINDOWS: "1" CODER_SIGN_DARWIN: "1" + CODER_WINDOWS_RESOURCES: "1" AC_CERTIFICATE_FILE: /tmp/apple_cert.p12 AC_CERTIFICATE_PASSWORD_FILE: /tmp/apple_cert_password.txt AC_APIKEY_ISSUER_ID: ${{ secrets.AC_APIKEY_ISSUER_ID }} diff --git a/buildinfo/resources/.gitignore b/buildinfo/resources/.gitignore new file mode 100644 index 0000000000000..40679b193bdf9 --- /dev/null +++ b/buildinfo/resources/.gitignore @@ -0,0 +1 @@ +*.syso diff --git a/buildinfo/resources/resources.go b/buildinfo/resources/resources.go new file mode 100644 index 0000000000000..cd1e3e70af2b7 --- /dev/null +++ b/buildinfo/resources/resources.go @@ -0,0 +1,8 @@ +// This package is used for embedding .syso resource files into the binary +// during build and does not contain any code. During build, .syso files will be +// dropped in this directory and then removed after the build completes. +// +// This package must be imported by all binaries for this to work. +// +// See build_go.sh for more details. +package resources diff --git a/cmd/coder/main.go b/cmd/coder/main.go index 1c22d578d7160..27918798b3a12 100644 --- a/cmd/coder/main.go +++ b/cmd/coder/main.go @@ -8,6 +8,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/coder/coder/v2/agent/agentexec" + _ "github.com/coder/coder/v2/buildinfo/resources" "github.com/coder/coder/v2/cli" ) diff --git a/enterprise/cmd/coder/main.go b/enterprise/cmd/coder/main.go index 803903f390e5a..217cca324b762 100644 --- a/enterprise/cmd/coder/main.go +++ b/enterprise/cmd/coder/main.go @@ -8,6 +8,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/coder/coder/v2/agent/agentexec" + _ "github.com/coder/coder/v2/buildinfo/resources" entcli "github.com/coder/coder/v2/enterprise/cli" ) diff --git a/scripts/build_go.sh b/scripts/build_go.sh index 91fc3a1e4b3e3..3e23e15d8b962 100755 --- a/scripts/build_go.sh +++ b/scripts/build_go.sh @@ -36,17 +36,19 @@ source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" version="" os="${GOOS:-linux}" arch="${GOARCH:-amd64}" +output_path="" slim="${CODER_SLIM_BUILD:-0}" +agpl="${CODER_BUILD_AGPL:-0}" sign_darwin="${CODER_SIGN_DARWIN:-0}" sign_windows="${CODER_SIGN_WINDOWS:-0}" -bin_ident="com.coder.cli" -output_path="" -agpl="${CODER_BUILD_AGPL:-0}" boringcrypto=${CODER_BUILD_BORINGCRYPTO:-0} -debug=0 dylib=0 +windows_resources="${CODER_WINDOWS_RESOURCES:-0}" +debug=0 + +bin_ident="com.coder.cli" -args="$(getopt -o "" -l version:,os:,arch:,output:,slim,agpl,sign-darwin,boringcrypto,dylib,debug -- "$@")" +args="$(getopt -o "" -l version:,os:,arch:,output:,slim,agpl,sign-darwin,sign-windows,boringcrypto,dylib,windows-resources,debug -- "$@")" eval set -- "$args" while true; do case "$1" in @@ -79,6 +81,10 @@ while true; do sign_darwin=1 shift ;; + --sign-windows) + sign_windows=1 + shift + ;; --boringcrypto) boringcrypto=1 shift @@ -87,6 +93,10 @@ while true; do dylib=1 shift ;; + --windows-resources) + windows_resources=1 + shift + ;; --debug) debug=1 shift @@ -115,11 +125,13 @@ if [[ "$sign_darwin" == 1 ]]; then dependencies rcodesign requiredenvs AC_CERTIFICATE_FILE AC_CERTIFICATE_PASSWORD_FILE fi - if [[ "$sign_windows" == 1 ]]; then dependencies java requiredenvs JSIGN_PATH EV_KEYSTORE EV_KEY EV_CERTIFICATE_PATH EV_TSA_URL GCLOUD_ACCESS_TOKEN fi +if [[ "$windows_resources" == 1 ]]; then + dependencies go-winres +fi ldflags=( -X "'github.com/coder/coder/v2/buildinfo.tag=$version'" @@ -204,10 +216,100 @@ if [[ "$boringcrypto" == 1 ]]; then goexp="boringcrypto" fi +# On Windows, we use go-winres to embed the resources into the binary. +if [[ "$windows_resources" == 1 ]] && [[ "$os" == "windows" ]]; then + # Convert the version to a format that Windows understands. + # Remove any trailing data after a "+" or "-". + version_windows=$version + version_windows="${version_windows%+*}" + version_windows="${version_windows%-*}" + # If there wasn't any extra data, add a .0 to the version. Otherwise, add + # a .1 to the version to signify that this is not a release build so it can + # be distinguished from a release build. + non_release_build=0 + if [[ "$version_windows" == "$version" ]]; then + version_windows+=".0" + else + version_windows+=".1" + non_release_build=1 + fi + + if [[ ! "$version_windows" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-1]$ ]]; then + error "Computed invalid windows version format: $version_windows" + fi + + # File description changes based on slimness, AGPL status, and architecture. + file_description="Coder" + if [[ "$agpl" == 1 ]]; then + file_description+=" AGPL" + fi + if [[ "$slim" == 1 ]]; then + file_description+=" CLI" + fi + if [[ "$non_release_build" == 1 ]]; then + file_description+=" (development build)" + fi + + # Because this writes to a file with the OS and arch in the filename, we + # don't support concurrent builds for the same OS and arch (irregardless of + # slimness or AGPL status). + # + # This is fine since we only embed resources during dogfood and release + # builds, which use make (which will build all slim targets in parallel, + # then all non-slim targets in parallel). + expected_rsrc_file="./buildinfo/resources/resources_windows_${arch}.syso" + if [[ -f "$expected_rsrc_file" ]]; then + rm "$expected_rsrc_file" + fi + touch "$expected_rsrc_file" + + pushd ./buildinfo/resources + GOARCH="$arch" go-winres simply \ + --arch "$arch" \ + --out "resources" \ + --product-version "$version_windows" \ + --file-version "$version_windows" \ + --manifest "cli" \ + --file-description "$file_description" \ + --product-name "Coder" \ + --copyright "Copyright $(date +%Y) Coder Technologies Inc." \ + --original-filename "coder.exe" \ + --icon ../../scripts/win-installer/coder.ico + popd + + if [[ ! -f "$expected_rsrc_file" ]]; then + error "Failed to generate $expected_rsrc_file" + fi +fi + +set +e GOEXPERIMENT="$goexp" CGO_ENABLED="$cgo" GOOS="$os" GOARCH="$arch" GOARM="$arm_version" \ go build \ "${build_args[@]}" \ "$cmd_path" 1>&2 +exit_code=$? +set -e + +# Clean up the resources file if it was generated. +if [[ "$windows_resources" == 1 ]] && [[ "$os" == "windows" ]]; then + rm "$expected_rsrc_file" +fi + +if [[ "$exit_code" != 0 ]]; then + exit "$exit_code" +fi + +# If we did embed resources, verify that they were included. +if [[ "$windows_resources" == 1 ]] && [[ "$os" == "windows" ]]; then + winres_dir=$(mktemp -d) + if ! go-winres extract --dir "$winres_dir" "$output_path" 1>&2; then + rm -rf "$winres_dir" + error "Compiled binary does not contain embedded resources" + fi + # If go-winres didn't return an error, it means it did find embedded + # resources. + rm -rf "$winres_dir" +fi if [[ "$sign_darwin" == 1 ]] && [[ "$os" == "darwin" ]]; then execrelative ./sign_darwin.sh "$output_path" "$bin_ident" 1>&2 From d2c54b36d9e39b84d043b62800c73c5c18cd9fe5 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 26 Feb 2025 02:41:31 +0000 Subject: [PATCH 2/6] test CI --- .github/workflows/ci.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cfa73ec597d61..c264fcdef0e20 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1018,7 +1018,7 @@ jobs: needs: - changes - build-dylib - if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork + #if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-22.04' }} permissions: packages: write # Needed to push images to ghcr.io @@ -1128,6 +1128,7 @@ jobs: JSIGN_PATH: /tmp/jsign-6.0.jar - name: Build Linux Docker images + if: github.ref == 'refs/heads/main' id: build-docker env: CODER_IMAGE_BASE: ghcr.io/coder/coder-preview @@ -1183,7 +1184,7 @@ jobs: prune-untagged: true - name: Upload build artifacts - if: github.ref == 'refs/heads/main' + #if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: coder From cf9fc04d9d48659472f068b673de051e484c3374 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 26 Feb 2025 02:47:38 +0000 Subject: [PATCH 3/6] fix: add permission for gcloud auth --- .github/workflows/ci.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c264fcdef0e20..3aa6f01fb3ffe 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1021,7 +1021,10 @@ jobs: #if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-22.04' }} permissions: - packages: write # Needed to push images to ghcr.io + # Necessary to push docker images to ghcr.io. + packages: write + # Necessary for GCP authentication (https://github.com/google-github-actions/setup-gcloud#usage) + id-token: write env: DOCKER_CLI_EXPERIMENTAL: "enabled" outputs: From 970bf8a6871e7bbe4a00e4d6cc793295bba910a5 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 26 Feb 2025 03:00:02 +0000 Subject: [PATCH 4/6] test CI 2 --- .github/workflows/ci.yaml | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3aa6f01fb3ffe..45fdbbeba1b34 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1017,7 +1017,6 @@ jobs: # to main branch. needs: - changes - - build-dylib #if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-22.04' }} permissions: @@ -1091,17 +1090,17 @@ jobs: - name: Setup GCloud SDK uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4 - - name: Download dylibs - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - with: - name: dylibs - path: ./build - - - name: Insert dylibs - run: | - mv ./build/*amd64.dylib ./site/out/bin/coder-vpn-darwin-amd64.dylib - mv ./build/*arm64.dylib ./site/out/bin/coder-vpn-darwin-arm64.dylib - mv ./build/*arm64.h ./site/out/bin/coder-vpn-darwin-dylib.h + #- name: Download dylibs + # uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + # with: + # name: dylibs + # path: ./build + + #- name: Insert dylibs + # run: | + # mv ./build/*amd64.dylib ./site/out/bin/coder-vpn-darwin-amd64.dylib + # mv ./build/*arm64.dylib ./site/out/bin/coder-vpn-darwin-arm64.dylib + # mv ./build/*arm64.h ./site/out/bin/coder-vpn-darwin-dylib.h - name: Build run: | From 35dc760a7671492c4390b18cd5464278fa9b4933 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 26 Feb 2025 03:23:16 +0000 Subject: [PATCH 5/6] Revert "test CI 2" This reverts commit 970bf8a6871e7bbe4a00e4d6cc793295bba910a5. --- .github/workflows/ci.yaml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 45fdbbeba1b34..3aa6f01fb3ffe 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1017,6 +1017,7 @@ jobs: # to main branch. needs: - changes + - build-dylib #if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-22.04' }} permissions: @@ -1090,17 +1091,17 @@ jobs: - name: Setup GCloud SDK uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4 - #- name: Download dylibs - # uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - # with: - # name: dylibs - # path: ./build - - #- name: Insert dylibs - # run: | - # mv ./build/*amd64.dylib ./site/out/bin/coder-vpn-darwin-amd64.dylib - # mv ./build/*arm64.dylib ./site/out/bin/coder-vpn-darwin-arm64.dylib - # mv ./build/*arm64.h ./site/out/bin/coder-vpn-darwin-dylib.h + - name: Download dylibs + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: dylibs + path: ./build + + - name: Insert dylibs + run: | + mv ./build/*amd64.dylib ./site/out/bin/coder-vpn-darwin-amd64.dylib + mv ./build/*arm64.dylib ./site/out/bin/coder-vpn-darwin-arm64.dylib + mv ./build/*arm64.h ./site/out/bin/coder-vpn-darwin-dylib.h - name: Build run: | From 5d9c439694bd6c8e211cb2b65fd29b686b93805f Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 26 Feb 2025 03:23:23 +0000 Subject: [PATCH 6/6] Revert "test CI" This reverts commit d2c54b36d9e39b84d043b62800c73c5c18cd9fe5. --- .github/workflows/ci.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3aa6f01fb3ffe..fbc4b9f373cfc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1018,7 +1018,7 @@ jobs: needs: - changes - build-dylib - #if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork + if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-22.04' }} permissions: # Necessary to push docker images to ghcr.io. @@ -1131,7 +1131,6 @@ jobs: JSIGN_PATH: /tmp/jsign-6.0.jar - name: Build Linux Docker images - if: github.ref == 'refs/heads/main' id: build-docker env: CODER_IMAGE_BASE: ghcr.io/coder/coder-preview @@ -1187,7 +1186,7 @@ jobs: prune-untagged: true - name: Upload build artifacts - #if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: coder