Changeset 0.24.3 (#159)

This commit is contained in:
2026-03-07 20:49:23 +00:00
parent ea082e2016
commit 937be26578
20 changed files with 836 additions and 29 deletions

View File

@@ -194,6 +194,10 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
}
channelID := req.ChannelID
if channelID == "" {
// v0.24.3: Workflow API routes have channel in URL param
channelID = c.Param("id")
}
if channelID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "channel_id is required"})
return
@@ -201,13 +205,25 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
userID := getUserID(c)
// Verify participation: check channel_participants first, fall back to
// legacy channels.user_id ownership for direct channels.
isParticipant, _ := h.stores.Channels.IsParticipant(c.Request.Context(), channelID, "user", userID)
if !isParticipant {
if !userOwnsChannel(c, channelID, userID) {
// v0.24.3: Session participants are pre-validated by AuthOrSession middleware
if isSessionAuth(c) {
if !sessionCanAccessChannel(c, channelID) {
c.JSON(http.StatusForbidden, gin.H{"error": "session not authorized for this channel"})
return
}
// Use session_id as effective identity for cursor/participant tracking.
// persistMessage will record participant_type=user with this ID —
// acceptable for v0.24.3; v0.25.0 can refine to participant_type=session.
userID = c.GetString("session_id")
} else {
// Verify participation: check channel_participants first, fall back to
// legacy channels.user_id ownership for direct channels.
isParticipant, _ := h.stores.Channels.IsParticipant(c.Request.Context(), channelID, "user", userID)
if !isParticipant {
if !userOwnsChannel(c, channelID, userID) {
return
}
}
}
// ── ai_mode guard (v0.23.1) ────────────────────────────────────────────────
@@ -630,8 +646,10 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
// Budget enforcement and model allowlist only apply when the request draws
// from a team or global provider. BYOK (personal scope) is the user's money
// — no ceiling applies.
// v0.24.3: Session participants bypass user-level budget/allowlist checks.
// They use the workflow channel's allocated resources.
role, _ := c.Get("role")
if role != "admin" && providerScope != "personal" {
if role != "admin" && providerScope != "personal" && !isSessionAuth(c) {
// Token budget
if h.stores.Usage != nil {
budget, err := auth.ResolveTokenBudget(c.Request.Context(), h.stores, userID)