1import { execSync } from 'child_process' 4const routedIps = new Set<string>() 6type VmNet = {gw: string, subnetsA: {subnetInt: number, mask: number}[]} 7let vmNetCache: VmNet | null | undefined 9const ipToInt = (ip: string) => ip.split('.').reduce((acc, oct) => (acc << 8) + parseInt(oct), 0) >>> 0 11const getVmNet = (): VmNet | null => { 12 if (vmNetCache !== undefined) return vmNetCache 14 const routes = execSync('colima ssh -- ip -4 route show', {stdio: ['ignore', 'pipe', 'ignore'], timeout: 15000}).toString() 15 const gw = routes.match(/^default via (\d+\.\d+\.\d+\.\d+)/m)?.[1] 16 const subnetsA = [...routes.matchAll(/^(\d+\.\d+\.\d+\.\d+)\/(\d+) dev \S+ proto kernel/gm)] 17 .map(m => ({subnetInt: ipToInt(m[1]!), mask: (~0 << (32 - parseInt(m[2]!))) >>> 0})) 18 if (!gw || !subnetsA.length) return (vmNetCache = null) 19 return (vmNetCache = {gw, subnetsA}) 21 return (vmNetCache = null) 22 } // catch:userapproved — colima not the docker host / VM down: nothing to fix 25// colima/lima vz VMs default to a NAT subnet that can collide with the real LAN's subnet — 26// when they overlap, LAN hosts (e.g. the LAN registry) are swallowed by the VM's connected 27// route and build pulls/pushes fail with "no route to host". Punch a /32 host route via the 29export const ensureVmLanRoute = async ({hostNamesA}: {hostNamesA: (string | undefined)[]}) => { 30 if (process.platform !== 'darwin') return 31 for (const hostName of hostNamesA) { 32 if (!hostName) continue 35 ;({address: ip} = await dnsLookup(hostName, {family: 4})) 36 } catch { continue } // catch:userapproved — unresolvable host: let the build/push error surface it 37 if (routedIps.has(ip)) continue 38 const vmNet = getVmNet() 40 const ipInt = ipToInt(ip) 41 if (!vmNet.subnetsA.some(s => (ipInt & s.mask) === (s.subnetInt & s.mask))) continue 43 execSync(`colima ssh -- sudo ip route replace ${ip}/32 via ${vmNet.gw}`, {stdio: ['ignore', 'pipe', 'ignore'], timeout: 15000}) 44 console.log(`colima VM: routed ${ip}/32 via ${vmNet.gw} (LAN host inside VM NAT subnet)`) 46 } catch { /* VM route add failed — push will surface the real error */ } // catch:userapproved