Files
Hammerhead/cmd/hammerhead/main.go
T
VeillaxandClaude Sonnet 5.5 f521fa8668 Add the Hammerhead control plane
Dashboard and API, accounts (organizations, roles, invitations, 2FA, OIDC
single sign-on, API keys, revocable sessions), an encrypted SQLite database,
resource logins, alerts and /metrics, mail egress management with DKIM keys,
and the .env loader. Split out of the original single repository; depends on
Reef for the shared types. The end-to-end tests that run Hammerhead, Blacktip
and Bamboo together live in e2e/.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 02:50:03 -06:00

62 lines
2.0 KiB
Go

// Hammerhead is the control plane: web UI + API that tells blacktip and bamboo what to do.
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"
"git.veillax.com/Veillax/hammerhead"
"git.veillax.com/Veillax/hammerhead/internal/secretbox"
"git.veillax.com/Veillax/reef/dotenv"
)
func env(k, def string) string {
if v := os.Getenv(k); v != "" {
return v
}
return def
}
func main() {
// secrets come from a .env file (or the real environment), read before flags so flags can default to them
envFile := dotenv.ArgPath(os.Args[1:], ".env")
if used, err := dotenv.Load(envFile); err != nil {
log.Fatalf("read %s: %v", envFile, err)
} else if used != "" {
log.Printf("loaded settings from %s", used)
}
listen := flag.String("listen", env("HAMMERHEAD_LISTEN", ":8080"), "address for the web UI and API")
data := flag.String("data", env("HAMMERHEAD_DATA", "./hammerhead-data"), "directory for the database")
url := flag.String("url", env("HAMMERHEAD_URL", ""), "public URL people reach hammerhead at (used for login redirects and SSO); can also be set in Settings")
flag.String("env", ".env", "file to read secrets and settings from")
genkey := flag.Bool("genkey", false, "print a new random HAMMERHEAD_MASTER_KEY and exit")
flag.Parse()
if *genkey {
fmt.Println(secretbox.GenerateKey())
return
}
days, _ := strconv.Atoi(os.Getenv("HAMMERHEAD_LOG_DAYS"))
srv, err := hammerhead.New(*data, hammerhead.Options{
AdminEmail: os.Getenv("HAMMERHEAD_ADMIN_EMAIL"),
AdminPassword: os.Getenv("HAMMERHEAD_ADMIN_PASSWORD"),
DashboardURL: *url,
MasterKey: os.Getenv("HAMMERHEAD_MASTER_KEY"),
MetricsToken: os.Getenv("HAMMERHEAD_METRICS_TOKEN"),
LogRetentionDays: days,
})
if err != nil {
log.Fatal(err)
}
defer srv.Close()
log.Printf("hammerhead listening on %s (open it in a browser to finish setup)", *listen)
hs := &http.Server{Addr: *listen, Handler: srv.Handler(), ReadHeaderTimeout: 10 * time.Second}
log.Fatal(hs.ListenAndServe())
}