package main import ( "fmt" "net" "github.com/enmanuel/unibus/pkg/membership" ) // isLoopbackBind reports whether the --bind value keeps the service reachable // only from this host. An empty bind means "all interfaces" (public), and a // hostname we cannot resolve to a loopback literal is treated as public — the // conservative choice, so an unusual bind never silently slips past the guard. func isLoopbackBind(bind string) bool { switch bind { case "localhost": return true case "": return false // empty binds every interface } ip := net.ParseIP(bind) if ip == nil { return false // a hostname we can't classify: assume public } return ip.IsLoopback() } // validateBootConfig is the fail-open guard (audit H2). It refuses any startup // configuration that would expose the bus without enforced authentication: // // - a non-loopback --bind without --bus-auth enforce (the data plane and // control plane would both accept anyone), and // - --tls-cert/--tls-key without --bus-auth enforce (TLS encrypts the channel // but authenticates no one — encrypted access for everybody is still open). // // It is a pure function of the parsed flags so the command can fail fast at // startup and tests can assert the policy without booting a server. func validateBootConfig(bind string, mode membership.AuthMode, tlsCert, tlsKey string) error { if !isLoopbackBind(bind) && mode != membership.AuthEnforce { return fmt.Errorf( "refusing to start: --bind %q is not loopback but --bus-auth is %q; a public bind requires --bus-auth enforce (or bind 127.0.0.1 for local dev)", bind, mode) } if (tlsCert != "" || tlsKey != "") && mode != membership.AuthEnforce { return fmt.Errorf( "refusing to start: --tls-cert/--tls-key set but --bus-auth is %q; TLS without enforced auth is fail-open (encrypted channel, no authentication) — set --bus-auth enforce", mode) } return nil }