#!/usr/bin/env python3
# Заплатка тулчейна Go 1.26 под macOS 10.15 для сборки агента NetBird.
# Go 1.25+ проверяет цепочку сертификатов через SecTrustCopyCertificateChain — её нет до macOS 12, и собранный бинарник на Catalina не стартует: dyld: Symbol not found. Возвращаем вызов из Go 1.24 (SecTrustGetCertificateCount + SecTrustGetCertificateAtIndex, есть с 10.7) и ставим в LC_BUILD_VERSION минимальную macOS 10.15 вместо 12.0 для amd64.
#
#   python3 scripts/nb_macos_legacy_patch_go.py <GOROOT>
import sys
from pathlib import Path

GOROOT = Path(sys.argv[1])


def patch(rel, old, new):
    p = GOROOT / "src" / rel
    s = p.read_text(encoding="utf-8")
    if new in s:
        return
    if s.count(old) != 1:
        sys.exit(f"{rel}: фрагмент для заплатки найден {s.count(old)} раз вместо одного — Go не той версии, под которую писалась заплатка")
    p.write_text(s.replace(old, new), encoding="utf-8")


patch("crypto/x509/internal/macos/security.go",
      '''//go:cgo_import_dynamic x509_SecTrustCopyCertificateChain SecTrustCopyCertificateChain "/System/Library/Frameworks/Security.framework/Versions/A/Security"

func SecTrustCopyCertificateChain(trustObj CFRef) (CFRef, error) {
	ret := syscall(abi.FuncPCABI0(x509_SecTrustCopyCertificateChain_trampoline), uintptr(trustObj), 0, 0, 0, 0, 0)
	if ret == 0 {
		return 0, OSStatus{"SecTrustCopyCertificateChain", int32(ret)}
	}
	return CFRef(ret), nil
}
func x509_SecTrustCopyCertificateChain_trampoline()
''',
      '''//go:cgo_import_dynamic x509_SecTrustGetCertificateCount SecTrustGetCertificateCount "/System/Library/Frameworks/Security.framework/Versions/A/Security"

func SecTrustGetCertificateCount(trustObj CFRef) int {
	ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateCount_trampoline), uintptr(trustObj), 0, 0, 0, 0, 0)
	return int(ret)
}
func x509_SecTrustGetCertificateCount_trampoline()

//go:cgo_import_dynamic x509_SecTrustGetCertificateAtIndex SecTrustGetCertificateAtIndex "/System/Library/Frameworks/Security.framework/Versions/A/Security"

func SecTrustGetCertificateAtIndex(trustObj CFRef, i int) (CFRef, error) {
	ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateAtIndex_trampoline), uintptr(trustObj), uintptr(i), 0, 0, 0, 0)
	if ret == 0 {
		return 0, OSStatus{"SecTrustGetCertificateAtIndex", int32(ret)}
	}
	return CFRef(ret), nil
}
func x509_SecTrustGetCertificateAtIndex_trampoline()
''')

patch("crypto/x509/internal/macos/security.s",
      '''TEXT ·x509_SecTrustCopyCertificateChain_trampoline(SB),NOSPLIT,$0-0
	JMP x509_SecTrustCopyCertificateChain(SB)
''',
      '''TEXT ·x509_SecTrustGetCertificateCount_trampoline(SB),NOSPLIT,$0-0
	JMP x509_SecTrustGetCertificateCount(SB)
TEXT ·x509_SecTrustGetCertificateAtIndex_trampoline(SB),NOSPLIT,$0-0
	JMP x509_SecTrustGetCertificateAtIndex(SB)
''')

patch("crypto/x509/root_darwin.go",
      '''	chainRef, err := macos.SecTrustCopyCertificateChain(trustObj)
	if err != nil {
		return nil, err
	}
	defer macos.CFRelease(chainRef)
	for i := 0; i < macos.CFArrayGetCount(chainRef); i++ {
		certRef := macos.CFArrayGetValueAtIndex(chainRef, i)
		cert, err := exportCertificate(certRef)
''',
      '''	numCerts := macos.SecTrustGetCertificateCount(trustObj)
	for i := 0; i < numCerts; i++ {
		certRef, err := macos.SecTrustGetCertificateAtIndex(trustObj, i)
		if err != nil {
			return nil, err
		}
		cert, err := exportCertificate(certRef)
''')

# Линкер: amd64 получает свою ветку с 10.15, arm64 остаётся на 12.0 — его не собираем.
patch("cmd/link/internal/ld/macho.go",
      "\t\t\tcase sys.ARM64, sys.AMD64:\n",
      "\t\t\tcase sys.AMD64:\n\t\t\t\tversion = 10<<16 | 15<<8 | 0<<0 // 10.15.0\n\t\t\tcase sys.ARM64:\n")

print("patched", GOROOT)
