- modules/pier: Host contract, mcp.* config, catalog compiled from pact.HasMCP (prefixing, route binding, guard resolution, schema reflection, annotations), per-request identity through the published verifier and resolvers, built-in backend guard provider, in-process dispatch with the bouncer marker, per-identity SDK server with the per-request re-filter, stateful session router with rehydration over a memory store, audit lines - modules/surf/pier_on.go: the summercms_mcp hook adapting the router to pier.Host; the untagged hello binary carries no SDK - go.mod: go-sdk v1.8.0 and jsonschema-go v0.4.3 (decision note committed before this change) - TestPierTracerSmoke: SDK client lists and calls acme_echo end to end through surf's compiled guard chain; README and root table row
72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package pier
|
|
|
|
import (
|
|
"log/slog"
|
|
"time"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/diary"
|
|
)
|
|
|
|
// LogComponent is the diary component pier logs under.
|
|
const LogComponent = "pier"
|
|
|
|
// sessionPrefixLen is how much of a session id the audit lines show.
|
|
const sessionPrefixLen = 8
|
|
|
|
// stateless is the session value of a call served on the stateless path.
|
|
const stateless = "stateless"
|
|
|
|
// logger is the module's logger (component pier).
|
|
func logger() *slog.Logger {
|
|
return diary.For(LogComponent)
|
|
}
|
|
|
|
// sessionPrefix shortens a session id for logging; a stateless call logs
|
|
// "stateless".
|
|
func sessionPrefix(id string) string {
|
|
if id == "" {
|
|
return stateless
|
|
}
|
|
if len(id) > sessionPrefixLen {
|
|
return id[:sessionPrefixLen]
|
|
}
|
|
return id
|
|
}
|
|
|
|
// logToolCall writes the one audit line per tool call (D-23): the tool,
|
|
// its guard, the frontend user id (0 when none), the backend admin id (0
|
|
// when none), the OAuth client id, the token kind, the session prefix, the
|
|
// route's status and the duration. Never the arguments, the body or a token.
|
|
func logToolCall(log *slog.Logger, id Identity, t *tool, session string, status int, took time.Duration) {
|
|
var userID, adminID uint
|
|
var clientID string
|
|
if id.Frontend != nil {
|
|
userID = id.Frontend.UserID
|
|
clientID = id.Frontend.ClientID
|
|
}
|
|
if id.Backend != nil {
|
|
adminID = id.Backend.UserID
|
|
if clientID == "" {
|
|
clientID = id.Backend.ClientID
|
|
}
|
|
}
|
|
log.Info("pier: tool call",
|
|
"tool", t.name,
|
|
"guard", t.guardName,
|
|
"user_id", userID,
|
|
"admin_id", adminID,
|
|
"client_id", clientID,
|
|
"token_kind", id.TokenKind,
|
|
"session", sessionPrefix(session),
|
|
"status", status,
|
|
"duration_ms", took.Milliseconds(),
|
|
)
|
|
}
|
|
|
|
// logSession writes one line per session lifecycle step (open, rehydrate,
|
|
// end, binding_refused, expired) with the session prefix and the binding,
|
|
// never the token.
|
|
func logSession(log *slog.Logger, step, session, binding string) {
|
|
log.Info("pier: session", "step", step, "session", sessionPrefix(session), "binding", binding)
|
|
}
|