The hourly release of ADR 0229's brake still ended in the mesh acting alone on a mistake. A consumer now stays active until the same unasked set holds for five passes, waits for a person past three or half of those held, is disabled and marked rather than withdrawn, comes back as it was when asked again, and is deleted only through the provider's delete tool. The backend keeps the mark, so a restart forgets nothing and finds what was withdrawn before.
71 lines
2.5 KiB
Go
71 lines
2.5 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())
|
|
|
|
var h *Harness
|
|
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())
|
|
}
|
|
// The retirement tools beside keycloak's own (novox/hq ADR 0230).
|
|
if err := stdio.Serve("", append(Tools(kc, guard), RetirementTools(h)...)); err != nil {
|
|
say("%v", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|