Files
act/common/outbound_ip.go
zeekayandHanzo Dev 873e28c9b4 fork act model + exprparser from gitea.com/gitea/runner
The forge needs to PARSE and EVALUATE workflows: model, exprparser, and the two
small helper packages they use. It does not need to run them — that is the
runner process, and a container runtime is 12000 of the 15754 lines in the
upstream act subtree.

So this is the 3619 lines that a forge actually calls, not a fork of the whole
engine. gitea.com/gitea/runner was the last gitea.com dependency in
hanzoai/git.

Pins match upstream (actionlint v1.7.12 with go.yaml.in/yaml/v4 v4.0.0-rc.3 —
the two are version-coupled and a free resolution of actionlint does not build)
and go 1.26, which exprparser needs for reflect.Fields.

Upstream MIT notices retained; ours added above them.

All four packages green.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 18:44:23 -07:00

81 lines
1.9 KiB
Go

// Copyright 2026 Hanzo AI, Inc. All rights reserved.
// Copyright 2023 The Gitea Authors. All rights reserved.
// Copyright 2021 The nektos/act Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package common
import (
"net"
"sort"
"strings"
)
// GetOutboundIP returns an outbound IP address of this machine.
// It tries to access the internet and returns the local IP address of the connection.
// If the machine cannot access the internet, it returns a preferred IP address from network interfaces.
// It returns nil if no IP address is found.
func GetOutboundIP() net.IP {
// See https://stackoverflow.com/a/37382208
conn, err := net.Dial("udp", "8.8.8.8:80")
if err == nil {
defer conn.Close()
return conn.LocalAddr().(*net.UDPAddr).IP
}
// So the machine cannot access the internet. Pick an IP address from network interfaces.
if ifs, err := net.Interfaces(); err == nil {
type IP struct {
net.IP
net.Interface
}
var ips []IP
for _, i := range ifs {
if addrs, err := i.Addrs(); err == nil {
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip.IsGlobalUnicast() {
ips = append(ips, IP{ip, i})
}
}
}
}
if len(ips) > 1 {
sort.Slice(ips, func(i, j int) bool {
ifi := ips[i].Interface
ifj := ips[j].Interface
// ethernet is preferred
if vi, vj := strings.HasPrefix(ifi.Name, "e"), strings.HasPrefix(ifj.Name, "e"); vi != vj {
return vi
}
ipi := ips[i].IP
ipj := ips[j].IP
// IPv4 is preferred
if vi, vj := ipi.To4() != nil, ipj.To4() != nil; vi != vj {
return vi
}
// en0 is preferred to en1
if ifi.Name != ifj.Name {
return ifi.Name < ifj.Name
}
// fallback
return ipi.String() < ipj.String()
})
return ips[0].IP
}
}
return nil
}