Files
mesh-catalog/modules/keycloak/cmd/keycloak-provider/main.go
T
jochen 77fb1ecfb2 keycloak: port to Go and repair an admin that refuses the mesh's secret
Twice the identity provider's admin kept an older password than the one the
mesh minted (an adopted, then a moved database), and the provisioner failed
every consumer until it was repaired by hand (hq issue 179). The module now
checks the admin's login and repairs a refusal itself through the server's
bootstrap command, verifies, brakes a failed repair and announces it, and
stops asking the server while refused. Ported to Go to change it.
2026-10-06 00:13:42 +02:00

69 lines
2.4 KiB
Go

// keycloak-provider: keycloak's code, one binary the node's runtime launches and speaks MCP to over
// stdio through the Go SDK (novox/hq ADR 0188, 0193). It serves keycloak's tools and, beside them,
// runs long: the provisioner that makes keycloak the provider of the mesh `oidc-client` interface,
// and the guard that keeps the admin logging in with the mesh's secret (novox/hq issue 179).
//
// stdout is the MCP channel; everything this module says, it says on stderr.
package main
import (
"context"
"os"
stdio "git.novox.be/novox/mesh-sdk/go"
)
func say(format string, args ...any) { logStderr("[keycloak] "+format, args...) }
// announce emits an event without letting a broker hiccup fail what it announces: the change already
// happened in Keycloak.
func announce(event string, body map[string]any) {
if err := stdio.Emit(event, body); err != nil {
say("emit %s failed: %v", event, err)
}
}
func main() {
kc, err := ClientFromEnv(os.Getenv)
if err != nil {
// Without the admin password there is nothing to serve, provision or guard; said, not fatal,
// so the runtime does not restart a process that cannot do better.
say("%v; serving no tools and provisioning nothing", err)
if err := stdio.Serve("", nil); err != nil {
say("%v", err)
os.Exit(1)
}
return
}
guard := &Guard{
KC: kc, Container: os.Getenv("MESH_KEYCLOAK_CONTAINER"),
Log: logStderr, Announce: announce,
}
kc.onRejected = guard.Nudge
go guard.Run(context.Background())
if receives := os.Getenv("MESH_RECEIVES"); receives == "" {
say("MESH_RECEIVES is not set — the provisioner cannot run without it")
} else if issuer, err := Issuer(os.Getenv); err != nil {
say("%v — the provisioner cannot run without it", err)
} else if realm, err := RealmOf(issuer); err != nil {
say("%v — the provisioner cannot run without it", err)
} else {
h := &Harness{
Resource: "oidc-client",
Receives: receives,
Adapter: provisioner{clients: OidcClients{KC: kc, Realm: realm}, guard: guard, announce: announce, log: logStderr},
Log: logStderr,
// A consumer failed for minutes is said on the bus, where the controller hears it and
// `status` names it (novox/hq ADR 0224).
Announce: announce,
Node: os.Getenv("MESH_NODE"),
}
go h.Run(context.Background())
}
if err := stdio.Serve("", Tools(kc, guard)); err != nil {
say("%v", err)
os.Exit(1)
}
}