diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3fc559..5132af0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,24 @@ jobs: # automatically by pip. python -m pip install -e cli + # Build the Go wrapper from source so the linux-amd64 CI runner has an + # executable at wrappers/go/policy-wrapper. The committed binary (if any) + # may have been built on a different OS/arch (e.g. macOS arm64) and will + # raise OSError: [Errno 8] Exec format error when invoked. + - name: Set up Go + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5 + with: + go-version: "1.22" + cache: true + cache-dependency-path: wrappers/go/go.mod + + - name: Build Go wrapper for the CI runner + run: | + set -euo pipefail + ( cd wrappers/go && go build -o policy-wrapper ./... ) + chmod +x wrappers/go/policy-wrapper + file wrappers/go/policy-wrapper + - name: Lint with ruff run: ruff check . diff --git a/.gitignore b/.gitignore index 8221e5b..d0bee1b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,10 @@ node_modules # Setuptools / pip metadata (build artifacts) *.egg-info/ +# Go wrapper binary -- built from source (wrappers/go/main.go) per-CI runner +# because a committed prebuilt binary is wrong-arch on other platforms. +wrappers/go/policy-wrapper +wrappers/go/policy-wrapper.exe + # Runtime/utility scripts (not source) ps_run.json diff --git a/tests/test_policy_contract.py b/tests/test_policy_contract.py index 52a3541..d073001 100644 --- a/tests/test_policy_contract.py +++ b/tests/test_policy_contract.py @@ -633,13 +633,15 @@ def _validate_wrapper_bundle( _validate_schema(payload, schema) def _build_go_binary(self, binary: Path) -> bool: - if binary.exists(): - return True - - go_source = binary.parent + # Always rebuild from source when `go` is available. Trusting a + # pre-existing binary is unsafe because it may have been built on a + # different OS/arch (e.g. macOS arm64 committed into the repo) and + # would raise OSError: [Errno 8] Exec format error on linux-amd64 + # CI runners. The Go module has no external deps, so this is fast. if shutil.which("go") is None: return False + go_source = binary.parent build = subprocess.run( ["go", "build", "-o", str(binary), "."], cwd=str(go_source), @@ -647,6 +649,8 @@ def _build_go_binary(self, binary: Path) -> bool: text=True, ) if build.returncode != 0: + print(build.stdout) + print(build.stderr, file=__import__("sys").stderr) return False return binary.exists() diff --git a/wrappers/go/policy-wrapper b/wrappers/go/policy-wrapper deleted file mode 100755 index c63b4c0..0000000 Binary files a/wrappers/go/policy-wrapper and /dev/null differ