From c92855d8d35a8c7f27a7d570dad224253a3197e8 Mon Sep 17 00:00:00 2001 From: Jeonghwan Lee Date: Tue, 21 Apr 2026 14:23:06 +0900 Subject: [PATCH 1/4] ci: per-platform build + cgo smoke matrix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit go test ./... already exercises internal/crypto cgo tests (context create, keygen, encrypt, decryptor open), which is the cheapest proof that the libevi + OpenSSL stack links and runs on each target. Wire that into a GitHub Actions matrix covering the five platforms the README claims to support: linux/amd64 ubuntu-latest linux/arm64 ubuntu-24.04-arm darwin/amd64 macos-13 darwin/arm64 macos-14 windows/amd64 windows-latest (MSYS2 mingw64) E2E is deliberately excluded — the test cluster is not stood up yet and tests/ is a separate module that ./... skips by default. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 67 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a5af843 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,67 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: test (${{ matrix.label }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest, label: linux/amd64 } + - { os: ubuntu-24.04-arm, label: linux/arm64 } + - { os: macos-13, label: darwin/amd64 } + - { os: macos-14, label: darwin/arm64 } + - { os: windows-latest, label: windows/amd64 } + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Install system deps (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y build-essential libssl-dev + + - name: Install system deps (macOS) + if: runner.os == 'macOS' + run: brew install openssl@3 + + - name: Set up MSYS2 (Windows) + if: runner.os == 'Windows' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + path-type: inherit + update: true + install: >- + mingw-w64-x86_64-gcc + mingw-w64-x86_64-openssl + + - name: Build & test (Unix) + if: runner.os != 'Windows' + run: | + go vet ./... + go build ./... + go test ./... + + - name: Build & test (Windows) + if: runner.os == 'Windows' + shell: msys2 {0} + run: | + go vet ./... + go build ./... + go test ./... From 2b46409333878bd42ed3ec0f9ef4f4f6998a8528 Mon Sep 17 00:00:00 2001 From: Jeonghwan Lee Date: Tue, 21 Apr 2026 14:27:39 +0900 Subject: [PATCH 2/4] ci: build darwin/amd64 on macos-14 via Rosetta 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macos-13 Intel runners are on the deprecation track; consolidate onto macos-14 and produce the darwin/amd64 slice as a cross-build from the Apple Silicon host instead: - clang -arch x86_64 for cgo compile + link - Intel Homebrew at /usr/local for x86_64 openssl@3 (the existing cgo darwin,amd64 LDFLAGS already point there as the first -L candidate) - Rosetta 2 to exec the x86_64 test binary that `go test` produces Locally verified on a darwin/arm64 host that the link reaches libevi cleanly and only fails on the missing x86_64 libssl — exactly the gap the Intel brew step closes on CI. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5af843..7c80423 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,8 +19,8 @@ jobs: include: - { os: ubuntu-latest, label: linux/amd64 } - { os: ubuntu-24.04-arm, label: linux/arm64 } - - { os: macos-13, label: darwin/amd64 } - { os: macos-14, label: darwin/arm64 } + - { os: macos-14, label: darwin/amd64 } # cross-built on arm64, run via Rosetta 2 - { os: windows-latest, label: windows/amd64 } steps: - uses: actions/checkout@v4 @@ -36,10 +36,21 @@ jobs: sudo apt-get update sudo apt-get install -y build-essential libssl-dev - - name: Install system deps (macOS) - if: runner.os == 'macOS' + - name: Install system deps (darwin/arm64) + if: matrix.label == 'darwin/arm64' run: brew install openssl@3 + - name: Install system deps (darwin/amd64 via Rosetta) + if: matrix.label == 'darwin/amd64' + run: | + # Rosetta 2 is needed to exec x86_64 test binaries on Apple Silicon + # runners. Idempotent — a no-op if already installed. + softwareupdate --install-rosetta --agree-to-license || true + # Intel Homebrew at /usr/local provides x86_64 openssl@3, which + # the cgo darwin,amd64 LDFLAGS already point at. + arch -x86_64 /bin/bash -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' + arch -x86_64 /usr/local/bin/brew install openssl@3 + - name: Set up MSYS2 (Windows) if: runner.os == 'Windows' uses: msys2/setup-msys2@v2 @@ -51,8 +62,20 @@ jobs: mingw-w64-x86_64-gcc mingw-w64-x86_64-openssl - - name: Build & test (Unix) - if: runner.os != 'Windows' + - name: Build & test (native) + if: runner.os != 'Windows' && matrix.label != 'darwin/amd64' + run: | + go vet ./... + go build ./... + go test ./... + + - name: Build & test (darwin/amd64 cross via Rosetta) + if: matrix.label == 'darwin/amd64' + env: + GOARCH: amd64 + CGO_ENABLED: "1" + CC: clang -arch x86_64 + CXX: clang++ -arch x86_64 run: | go vet ./... go build ./... From 22c1b3a42ce0dbf39b9591ead24de9d74866f247 Mon Sep 17 00:00:00 2001 From: Jeonghwan Lee Date: Tue, 21 Apr 2026 14:35:10 +0900 Subject: [PATCH 3/4] ci: allow manual dispatch for pre-merge validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lets us trigger the matrix on a feature branch before opening the PR, which is how we want to iterate on this workflow itself — tweak, dispatch, observe, repeat — without cluttering the history with "fix CI" commits on main. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c80423..9aa664e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,7 @@ on: push: branches: [main] pull_request: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 0be44e6642908976624f8d36617de007a59cf76d Mon Sep 17 00:00:00 2001 From: Jeonghwan Lee Date: Tue, 21 Apr 2026 14:41:17 +0900 Subject: [PATCH 4/4] fix(crypto): define EVI_STATIC so Windows links against the static archive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Windows, EVI/Export.hpp resolves EVI_API to __declspec(dllimport) unless EVI_STATIC is defined. That caused mingw to emit __imp_ references for every evi::KeyManager and evi::makeKeyManager call in keymanager_shim.cpp, which libevi_crypto.a does not provide — it exports the bare mangled symbols (confirmed via nm on the bundled Windows archive). Linux/macOS escaped the issue only because their Export.hpp branch is a no-op visibility attribute. Define EVI_STATIC globally in the cgo CPPFLAGS so the import/export annotation is neutralised on every platform, matching the fact that we always consume libevi as static archives. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/crypto/cryptocgo.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/crypto/cryptocgo.go b/internal/crypto/cryptocgo.go index e6da8ec..9fbb33c 100644 --- a/internal/crypto/cryptocgo.go +++ b/internal/crypto/cryptocgo.go @@ -35,7 +35,13 @@ package crypto // Intel; both search paths are supplied so the linker picks whichever // exists. Linux assumes system libssl-dev. Windows assumes MSYS2 // mingw-w64-x86_64-openssl. -#cgo CPPFLAGS: -I${SRCDIR}/../../third_party/evi/include +// EVI_STATIC tells EVI/Export.hpp to leave EVI_API empty on all +// platforms. We link against the bundled static archives +// (libevi_c_api.a, libevi_crypto.a), so Windows must not treat the +// API-annotated class/function declarations in km/KeyManager.hpp as +// __declspec(dllimport) — otherwise mingw emits __imp_ +// references that the static archive does not provide. +#cgo CPPFLAGS: -I${SRCDIR}/../../third_party/evi/include -DEVI_STATIC #cgo CXXFLAGS: -std=c++17 #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/../../third_party/evi/darwin_arm64/lib -levi_c_api -levi_crypto -ldeb -lalea -L/opt/homebrew/opt/openssl@3/lib -L/usr/local/opt/openssl@3/lib -lssl -lcrypto -lc++ -lm #cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/../../third_party/evi/darwin_amd64/lib -levi_c_api -levi_crypto -ldeb -lalea -L/usr/local/opt/openssl@3/lib -L/opt/homebrew/opt/openssl@3/lib -lssl -lcrypto -lc++ -lm