feat: Phase 3 — MCP header fallback, LIKE-based consent window, and auth token fix for dsh integration

- X-Oikos-Session-Id header → context fallback for _session_id
- sessionIDFromArgsOrContext() reads from args, then header
- AssentWindowActive falls back to session-ID-only LIKE lookup
- windowActiveLike() for LIKE-pattern autonomy_settings queries
- mcpBearerToken: package-level resolved token replaces os.Getenv() in decide_approval
- Bump 0.36.0 → 0.37.0
This commit is contained in:
2026-08-16 16:35:34 +02:00
parent b98d7c24bf
commit 04aa1bd5e8
5 changed files with 354 additions and 11 deletions

View File

@@ -42,12 +42,25 @@ func (g *GovernanceRepo) SessionHasPlan(ctx context.Context, sessionID string) b
}
// AssentWindowActive checks the session-scoped assent window key set by
// chat assent and the approval-decide path.
// chat assent and the approval-decide path. When no agent is available (dsh),
// falls back to a session-ID-only LIKE lookup.
func (g *GovernanceRepo) AssentWindowActive(ctx context.Context, agentID domain.UUID, sessionID string) bool {
if agentID == "" || sessionID == "" {
if sessionID == "" {
return false // fail closed
}
return g.windowActive(ctx, "assent_window.agent:"+string(agentID)+".session:"+sessionID)
// Exact key lookup (nomos path)
if agentID != "" {
key := "assent_window.agent:" + string(agentID) + ".session:" + sessionID
if g.windowActive(ctx, key) {
return true
}
}
// Session-ID-only LIKE fallback (dsh path — no agent entity UUID).
// Any window with a matching `.session:<id>` suffix is active.
if g.windowActiveLike(ctx, "%.session:"+sessionID) {
return true
}
return false
}
// DestructiveWindowActive checks the target+session-scoped destructive
@@ -75,6 +88,22 @@ func (g *GovernanceRepo) windowActive(ctx context.Context, key string) bool {
return time.Now().UTC().Before(expires)
}
// windowActiveLike checks a LIKE pattern against autonomy_settings keys.
// Used by AssentWindowActive for session-ID-only fallback lookups (dsh path).
func (g *GovernanceRepo) windowActiveLike(ctx context.Context, pattern string) bool {
var expiresStr string
err := g.pool.QueryRow(ctx,
"SELECT value FROM autonomy_settings WHERE key LIKE $1", pattern).Scan(&expiresStr)
if err != nil {
return false
}
expires, err := time.Parse(time.RFC3339, expiresStr)
if err != nil {
return false
}
return time.Now().UTC().Before(expires)
}
// PendingApprovalCount returns the session's executions at pending_approval.
func (g *GovernanceRepo) PendingApprovalCount(ctx context.Context, sessionID string) int {
var n int