Files
go-sip/internal/store/ai_authorization.go
T

67 lines
2.5 KiB
Go

package store
import (
"encoding/json"
"errors"
"git.ipao.vip/rogee/go-sip/internal/ai"
"git.ipao.vip/rogee/go-sip/internal/contract"
)
// LoadAuthorizedAI never treats a cached configuration as permission to run.
// The latest received reply governs admission; rejection, revocation and expiry
// cannot fall back to an earlier successful reply.
func (s *Store) LoadAuthorizedAI(tenantID, tenantKey, version string) (ai.Snapshot, []byte, error) {
snapshot, err := s.LoadAIConfig(tenantID, tenantKey, version)
if err != nil {
return ai.Snapshot{}, nil, err
}
var raw []byte
if err := s.db.QueryRow(`SELECT r.response FROM ai_mq_requests r JOIN outbox o ON o.event_id=r.message_id
WHERE r.tenant_id=? AND r.tenant_key=? AND r.agent_version_id=? AND r.response IS NOT NULL
ORDER BY o.id DESC LIMIT 1`, tenantID, tenantKey, version).Scan(&raw); err != nil {
return ai.Snapshot{}, nil, err
}
response, err := contract.DecodeService(raw)
if err != nil {
return ai.Snapshot{}, nil, err
}
if response.Status != "ok" {
return ai.Snapshot{}, nil, errors.New("latest AI configuration authorization request was rejected")
}
var payload struct {
Authorization json.RawMessage `json:"authorization"`
}
if err := json.Unmarshal(response.Payload, &payload); err != nil {
return ai.Snapshot{}, nil, err
}
authorization, err := ai.ValidateAuthorization(payload.Authorization, snapshot, tenantID, tenantKey, s.now())
if err != nil {
return ai.Snapshot{}, nil, err
}
// Revocation is a permanent fact for this grant identity, even if a later
// correlated request returns an older non-revoked representation.
rows, err := s.db.Query(`SELECT json_extract(response,'$.payload.authorization') FROM ai_mq_requests
WHERE tenant_id=? AND tenant_key=? AND agent_version_id=?
AND json_extract(response,'$.payload.authorization.authorization_id')=?
AND json_extract(response,'$.payload.authorization.revoked')=1`, tenantID, tenantKey, version, authorization.AuthorizationID)
if err != nil {
return ai.Snapshot{}, nil, err
}
defer rows.Close()
for rows.Next() {
var revokedRaw []byte
if err := rows.Scan(&revokedRaw); err != nil {
return ai.Snapshot{}, nil, err
}
if _, err := ai.DecodeBoundAuthorization(revokedRaw, snapshot, tenantID, tenantKey); err != nil {
return ai.Snapshot{}, nil, err
}
return ai.Snapshot{}, nil, errors.New("AI authorization has a persisted revocation")
}
if err := rows.Err(); err != nil {
return ai.Snapshot{}, nil, err
}
return snapshot, append([]byte(nil), payload.Authorization...), nil
}