From ae0b93575e260c3425ae72a1011d2a12d1464c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Wed, 13 Apr 2022 19:58:03 +0200 Subject: [PATCH] Add support for installing binary extensions on M1 Macs If the extension publishes an amd64 binary and Rosetta is available, use that binary as it will most likely work. If the extension publishes an arm64 binary, make sure to codesign it after downloading so that the OS allows its execution. --- pkg/cmd/extension/manager.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pkg/cmd/extension/manager.go b/pkg/cmd/extension/manager.go index 6819ee7c4..44a9cbab4 100644 --- a/pkg/cmd/extension/manager.go +++ b/pkg/cmd/extension/manager.go @@ -371,14 +371,28 @@ func (m *Manager) installBin(repo ghrepo.Interface, target string) error { } platform, ext := m.platform() + isMacARM := platform == "darwin-arm64" + trueARMBinary := false + var asset *releaseAsset for _, a := range r.Assets { if strings.HasSuffix(a.Name, platform+ext) { asset = &a + trueARMBinary = isMacARM break } } + // if an arm64 binary is unavailable, fall back to amd64 if it can be executed through Rosetta 2 + if asset == nil && isMacARM && hasRosetta() { + for _, a := range r.Assets { + if strings.HasSuffix(a.Name, "darwin-amd64") { + asset = &a + break + } + } + } + if asset == nil { return fmt.Errorf( "%[1]s unsupported for %[2]s. Open an issue: `gh issue create -R %[3]s/%[1]s -t'Support %[2]s'`", @@ -404,6 +418,11 @@ func (m *Manager) installBin(repo ghrepo.Interface, target string) error { if err != nil { return fmt.Errorf("failed to download asset %s: %w", asset.Name, err) } + if trueARMBinary { + if err := codesignBinary(binPath); err != nil { + return fmt.Errorf("failed to codesign downloaded binary: %w", err) + } + } } manifest := binManifest{ @@ -844,3 +863,17 @@ func possibleDists() []string { "windows-arm", } } + +func hasRosetta() bool { + _, err := os.Stat("/Library/Apple/usr/libexec/oah/libRosettaRuntime") + return err == nil +} + +func codesignBinary(binPath string) error { + codesignExe, err := safeexec.LookPath("codesign") + if err != nil { + return err + } + cmd := exec.Command(codesignExe, "--sign", "-", "--force", "--preserve-metadata=entitlements,requirements,flags,runtime", binPath) + return cmd.Run() +}