- InsertMetricSample now includes ts=now() (TimescaleDB hypertable requires it) - ssh-script: pass host and port separately (ssh uses -p flag, not host:port) - ssh-script: use OIKOS_SSH_USER from config/env, default root - Add -o LogLevel=ERROR to suppress SSH warnings polluting JSON output - Use Output() (stdout only) instead of CombinedOutput() - Set OIKOS_SSH_USER=root in scheduler docker-compose service
1608 lines
39 KiB
Go
1608 lines
39 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.29.0
|
|
// source: operations.sql
|
|
|
|
package sqlcgen
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const getApprovalByID = `-- name: GetApprovalByID :one
|
|
SELECT entity_id, subject_entity_id, action, risk_class, kind, payload, status, token_hash, expires_at, decided_at, decided_by, created_at, matrix_event_id, alert_sent_at FROM approvals WHERE entity_id = $1
|
|
`
|
|
|
|
func (q *Queries) GetApprovalByID(ctx context.Context, entityID uuid.UUID) (Approval, error) {
|
|
row := q.db.QueryRow(ctx, getApprovalByID, entityID)
|
|
var i Approval
|
|
err := row.Scan(
|
|
&i.EntityID,
|
|
&i.SubjectEntityID,
|
|
&i.Action,
|
|
&i.RiskClass,
|
|
&i.Kind,
|
|
&i.Payload,
|
|
&i.Status,
|
|
&i.TokenHash,
|
|
&i.ExpiresAt,
|
|
&i.DecidedAt,
|
|
&i.DecidedBy,
|
|
&i.CreatedAt,
|
|
&i.MatrixEventID,
|
|
&i.AlertSentAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getAutonomySetting = `-- name: GetAutonomySetting :one
|
|
SELECT value FROM autonomy_settings WHERE key = $1
|
|
`
|
|
|
|
func (q *Queries) GetAutonomySetting(ctx context.Context, key string) (string, error) {
|
|
row := q.db.QueryRow(ctx, getAutonomySetting, key)
|
|
var value string
|
|
err := row.Scan(&value)
|
|
return value, err
|
|
}
|
|
|
|
const getCheckDef = `-- name: GetCheckDef :one
|
|
SELECT entity_id, target_id, target_type, kind, config, interval_s, timeout_s, zone, enabled, updated_at FROM check_defs WHERE entity_id = $1
|
|
`
|
|
|
|
func (q *Queries) GetCheckDef(ctx context.Context, entityID uuid.UUID) (CheckDef, error) {
|
|
row := q.db.QueryRow(ctx, getCheckDef, entityID)
|
|
var i CheckDef
|
|
err := row.Scan(
|
|
&i.EntityID,
|
|
&i.TargetID,
|
|
&i.TargetType,
|
|
&i.Kind,
|
|
&i.Config,
|
|
&i.IntervalS,
|
|
&i.TimeoutS,
|
|
&i.Zone,
|
|
&i.Enabled,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getEntityStatus = `-- name: GetEntityStatus :one
|
|
SELECT entity_id, health, last_check_at, details, updated_at FROM entity_status WHERE entity_id = $1
|
|
`
|
|
|
|
func (q *Queries) GetEntityStatus(ctx context.Context, entityID uuid.UUID) (EntityStatus, error) {
|
|
row := q.db.QueryRow(ctx, getEntityStatus, entityID)
|
|
var i EntityStatus
|
|
err := row.Scan(
|
|
&i.EntityID,
|
|
&i.Health,
|
|
&i.LastCheckAt,
|
|
&i.Details,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getExecution = `-- name: GetExecution :one
|
|
SELECT entity_id, classification_id, signal_entity_id, target_entity_id, action, risk_class, approval_id, agent_id, skill_id, skill_version, status, result, duration_ms, verified, correlation_id, started_at, completed_at, created_at FROM executions WHERE entity_id = $1
|
|
`
|
|
|
|
func (q *Queries) GetExecution(ctx context.Context, entityID uuid.UUID) (Execution, error) {
|
|
row := q.db.QueryRow(ctx, getExecution, entityID)
|
|
var i Execution
|
|
err := row.Scan(
|
|
&i.EntityID,
|
|
&i.ClassificationID,
|
|
&i.SignalEntityID,
|
|
&i.TargetEntityID,
|
|
&i.Action,
|
|
&i.RiskClass,
|
|
&i.ApprovalID,
|
|
&i.AgentID,
|
|
&i.SkillID,
|
|
&i.SkillVersion,
|
|
&i.Status,
|
|
&i.Result,
|
|
&i.DurationMs,
|
|
&i.Verified,
|
|
&i.CorrelationID,
|
|
&i.StartedAt,
|
|
&i.CompletedAt,
|
|
&i.CreatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getFeedbackAfterWatermark = `-- name: GetFeedbackAfterWatermark :many
|
|
SELECT f.entity_id, f.execution_id, f.outcome, f.observation, f.lesson,
|
|
f.unexpected_side_effects, f.tags, f.created_at,
|
|
e.action, e.risk_class, e.target_entity_id,
|
|
et.name AS applies_type
|
|
FROM feedback f
|
|
JOIN executions e ON e.entity_id = f.execution_id
|
|
JOIN entities ent ON ent.id = e.target_entity_id
|
|
JOIN entity_types et ON et.name = ent.type
|
|
WHERE f.created_at > $1
|
|
ORDER BY f.created_at ASC
|
|
`
|
|
|
|
type GetFeedbackAfterWatermarkRow struct {
|
|
EntityID uuid.UUID
|
|
ExecutionID uuid.UUID
|
|
Outcome string
|
|
Observation *string
|
|
Lesson *string
|
|
UnexpectedSideEffects []string
|
|
Tags []string
|
|
CreatedAt time.Time
|
|
Action string
|
|
RiskClass string
|
|
TargetEntityID *uuid.UUID
|
|
AppliesType string
|
|
}
|
|
|
|
func (q *Queries) GetFeedbackAfterWatermark(ctx context.Context, createdAt time.Time) ([]GetFeedbackAfterWatermarkRow, error) {
|
|
rows, err := q.db.Query(ctx, getFeedbackAfterWatermark, createdAt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetFeedbackAfterWatermarkRow
|
|
for rows.Next() {
|
|
var i GetFeedbackAfterWatermarkRow
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.ExecutionID,
|
|
&i.Outcome,
|
|
&i.Observation,
|
|
&i.Lesson,
|
|
&i.UnexpectedSideEffects,
|
|
&i.Tags,
|
|
&i.CreatedAt,
|
|
&i.Action,
|
|
&i.RiskClass,
|
|
&i.TargetEntityID,
|
|
&i.AppliesType,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const getIdempotentResponse = `-- name: GetIdempotentResponse :one
|
|
SELECT response_code, response_body, request_hash FROM idempotency_keys
|
|
WHERE actor = $1 AND key = $2
|
|
`
|
|
|
|
type GetIdempotentResponseParams struct {
|
|
Actor string
|
|
Key string
|
|
}
|
|
|
|
type GetIdempotentResponseRow struct {
|
|
ResponseCode *int32
|
|
ResponseBody []byte
|
|
RequestHash string
|
|
}
|
|
|
|
func (q *Queries) GetIdempotentResponse(ctx context.Context, arg GetIdempotentResponseParams) (GetIdempotentResponseRow, error) {
|
|
row := q.db.QueryRow(ctx, getIdempotentResponse, arg.Actor, arg.Key)
|
|
var i GetIdempotentResponseRow
|
|
err := row.Scan(&i.ResponseCode, &i.ResponseBody, &i.RequestHash)
|
|
return i, err
|
|
}
|
|
|
|
const getOpenSignalsForAutoAct = `-- name: GetOpenSignalsForAutoAct :many
|
|
SELECT s.entity_id, s.kind, s.severity, s.target_entity_id, s.check_id, s.evidence, s.likely_cause, s.state, s.occurrence_count, s.first_seen_at, s.last_seen_at, s.flap_count, s.hold_down_until, s.mute_until, s.created_at, s.updated_at, c.entity_id AS classification_id, c.action, c.risk_class, c.route,
|
|
c.blast_radius, c.correlation_id, c.reasoning
|
|
FROM classifications c
|
|
JOIN signals s ON s.entity_id = c.signal_entity_id
|
|
LEFT JOIN executions e ON e.classification_id = c.entity_id
|
|
WHERE c.route = 'auto-act'
|
|
AND e.entity_id IS NULL
|
|
AND (s.hold_down_until IS NULL OR s.hold_down_until < now())
|
|
AND (s.mute_until IS NULL OR s.mute_until < now())
|
|
ORDER BY s.last_seen_at ASC
|
|
LIMIT $1
|
|
`
|
|
|
|
type GetOpenSignalsForAutoActRow struct {
|
|
EntityID uuid.UUID
|
|
Kind string
|
|
Severity string
|
|
TargetEntityID *uuid.UUID
|
|
CheckID *uuid.UUID
|
|
Evidence *string
|
|
LikelyCause *string
|
|
State string
|
|
OccurrenceCount int32
|
|
FirstSeenAt time.Time
|
|
LastSeenAt time.Time
|
|
FlapCount int32
|
|
HoldDownUntil *time.Time
|
|
MuteUntil *time.Time
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
ClassificationID uuid.UUID
|
|
Action string
|
|
RiskClass string
|
|
Route string
|
|
BlastRadius []uuid.UUID
|
|
CorrelationID string
|
|
Reasoning []byte
|
|
}
|
|
|
|
// Signals with auto-act classifications that haven't been executed yet
|
|
func (q *Queries) GetOpenSignalsForAutoAct(ctx context.Context, limit int32) ([]GetOpenSignalsForAutoActRow, error) {
|
|
rows, err := q.db.Query(ctx, getOpenSignalsForAutoAct, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetOpenSignalsForAutoActRow
|
|
for rows.Next() {
|
|
var i GetOpenSignalsForAutoActRow
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.Kind,
|
|
&i.Severity,
|
|
&i.TargetEntityID,
|
|
&i.CheckID,
|
|
&i.Evidence,
|
|
&i.LikelyCause,
|
|
&i.State,
|
|
&i.OccurrenceCount,
|
|
&i.FirstSeenAt,
|
|
&i.LastSeenAt,
|
|
&i.FlapCount,
|
|
&i.HoldDownUntil,
|
|
&i.MuteUntil,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.ClassificationID,
|
|
&i.Action,
|
|
&i.RiskClass,
|
|
&i.Route,
|
|
&i.BlastRadius,
|
|
&i.CorrelationID,
|
|
&i.Reasoning,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const getPattern = `-- name: GetPattern :one
|
|
SELECT entity_id, applies_type, action, pattern, confidence, evidence_count, success_count, failure_count, status, quarantined, version, last_validated_at, created_at FROM patterns WHERE applies_type = $1 AND action = $2
|
|
`
|
|
|
|
type GetPatternParams struct {
|
|
AppliesType string
|
|
Action string
|
|
}
|
|
|
|
func (q *Queries) GetPattern(ctx context.Context, arg GetPatternParams) (Pattern, error) {
|
|
row := q.db.QueryRow(ctx, getPattern, arg.AppliesType, arg.Action)
|
|
var i Pattern
|
|
err := row.Scan(
|
|
&i.EntityID,
|
|
&i.AppliesType,
|
|
&i.Action,
|
|
&i.Pattern,
|
|
&i.Confidence,
|
|
&i.EvidenceCount,
|
|
&i.SuccessCount,
|
|
&i.FailureCount,
|
|
&i.Status,
|
|
&i.Quarantined,
|
|
&i.Version,
|
|
&i.LastValidatedAt,
|
|
&i.CreatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const insertApproval = `-- name: InsertApproval :exec
|
|
INSERT INTO approvals (entity_id, subject_entity_id, action, risk_class, kind,
|
|
payload, status, token_hash, expires_at)
|
|
VALUES ($1, $2, $3, $4, $5, $6, 'pending', $7, $8)
|
|
`
|
|
|
|
type InsertApprovalParams struct {
|
|
EntityID uuid.UUID
|
|
SubjectEntityID *uuid.UUID
|
|
Action string
|
|
RiskClass string
|
|
Kind string
|
|
Payload []byte
|
|
TokenHash *string
|
|
ExpiresAt time.Time
|
|
}
|
|
|
|
func (q *Queries) InsertApproval(ctx context.Context, arg InsertApprovalParams) error {
|
|
_, err := q.db.Exec(ctx, insertApproval,
|
|
arg.EntityID,
|
|
arg.SubjectEntityID,
|
|
arg.Action,
|
|
arg.RiskClass,
|
|
arg.Kind,
|
|
arg.Payload,
|
|
arg.TokenHash,
|
|
arg.ExpiresAt,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertAuditEntry = `-- name: InsertAuditEntry :exec
|
|
INSERT INTO audit_log (actor_type, actor_id, action, entity_id, method, path,
|
|
status_code, detail, source_ip, correlation_id)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
`
|
|
|
|
type InsertAuditEntryParams struct {
|
|
ActorType string
|
|
ActorID *uuid.UUID
|
|
Action string
|
|
EntityID *uuid.UUID
|
|
Method *string
|
|
Path *string
|
|
StatusCode *int32
|
|
Detail []byte
|
|
SourceIp *string
|
|
CorrelationID *string
|
|
}
|
|
|
|
func (q *Queries) InsertAuditEntry(ctx context.Context, arg InsertAuditEntryParams) error {
|
|
_, err := q.db.Exec(ctx, insertAuditEntry,
|
|
arg.ActorType,
|
|
arg.ActorID,
|
|
arg.Action,
|
|
arg.EntityID,
|
|
arg.Method,
|
|
arg.Path,
|
|
arg.StatusCode,
|
|
arg.Detail,
|
|
arg.SourceIp,
|
|
arg.CorrelationID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertCheckDef = `-- name: InsertCheckDef :exec
|
|
INSERT INTO check_defs (entity_id, target_id, target_type, kind, config, interval_s, timeout_s, zone, enabled)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
`
|
|
|
|
type InsertCheckDefParams struct {
|
|
EntityID uuid.UUID
|
|
TargetID *uuid.UUID
|
|
TargetType *string
|
|
Kind string
|
|
Config []byte
|
|
IntervalS int32
|
|
TimeoutS int32
|
|
Zone *string
|
|
Enabled bool
|
|
}
|
|
|
|
func (q *Queries) InsertCheckDef(ctx context.Context, arg InsertCheckDefParams) error {
|
|
_, err := q.db.Exec(ctx, insertCheckDef,
|
|
arg.EntityID,
|
|
arg.TargetID,
|
|
arg.TargetType,
|
|
arg.Kind,
|
|
arg.Config,
|
|
arg.IntervalS,
|
|
arg.TimeoutS,
|
|
arg.Zone,
|
|
arg.Enabled,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertClassification = `-- name: InsertClassification :exec
|
|
INSERT INTO classifications (entity_id, signal_entity_id, target_entity_id, action,
|
|
recommended_action, risk_class, route, blast_radius, pattern_confidence,
|
|
skill_id, autonomy_check, reasoning, correlation_id)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
|
`
|
|
|
|
type InsertClassificationParams struct {
|
|
EntityID uuid.UUID
|
|
SignalEntityID *uuid.UUID
|
|
TargetEntityID *uuid.UUID
|
|
Action string
|
|
RecommendedAction []byte
|
|
RiskClass string
|
|
Route string
|
|
BlastRadius []uuid.UUID
|
|
PatternConfidence *float32
|
|
SkillID *uuid.UUID
|
|
AutonomyCheck *string
|
|
Reasoning []byte
|
|
CorrelationID string
|
|
}
|
|
|
|
func (q *Queries) InsertClassification(ctx context.Context, arg InsertClassificationParams) error {
|
|
_, err := q.db.Exec(ctx, insertClassification,
|
|
arg.EntityID,
|
|
arg.SignalEntityID,
|
|
arg.TargetEntityID,
|
|
arg.Action,
|
|
arg.RecommendedAction,
|
|
arg.RiskClass,
|
|
arg.Route,
|
|
arg.BlastRadius,
|
|
arg.PatternConfidence,
|
|
arg.SkillID,
|
|
arg.AutonomyCheck,
|
|
arg.Reasoning,
|
|
arg.CorrelationID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertEvent = `-- name: InsertEvent :one
|
|
INSERT INTO events (type, entity_id, severity, source, data, correlation_id)
|
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
RETURNING id, ts
|
|
`
|
|
|
|
type InsertEventParams struct {
|
|
Type string
|
|
EntityID *uuid.UUID
|
|
Severity string
|
|
Source string
|
|
Data []byte
|
|
CorrelationID *string
|
|
}
|
|
|
|
type InsertEventRow struct {
|
|
ID int64
|
|
Ts time.Time
|
|
}
|
|
|
|
func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) (InsertEventRow, error) {
|
|
row := q.db.QueryRow(ctx, insertEvent,
|
|
arg.Type,
|
|
arg.EntityID,
|
|
arg.Severity,
|
|
arg.Source,
|
|
arg.Data,
|
|
arg.CorrelationID,
|
|
)
|
|
var i InsertEventRow
|
|
err := row.Scan(&i.ID, &i.Ts)
|
|
return i, err
|
|
}
|
|
|
|
const insertExecution = `-- name: InsertExecution :exec
|
|
INSERT INTO executions (entity_id, classification_id, signal_entity_id,
|
|
target_entity_id, action, risk_class, approval_id, agent_id,
|
|
skill_id, skill_version, status, correlation_id)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'proposed', $11)
|
|
`
|
|
|
|
type InsertExecutionParams struct {
|
|
EntityID uuid.UUID
|
|
ClassificationID *uuid.UUID
|
|
SignalEntityID *uuid.UUID
|
|
TargetEntityID *uuid.UUID
|
|
Action string
|
|
RiskClass string
|
|
ApprovalID *uuid.UUID
|
|
AgentID *uuid.UUID
|
|
SkillID *uuid.UUID
|
|
SkillVersion *int32
|
|
CorrelationID string
|
|
}
|
|
|
|
func (q *Queries) InsertExecution(ctx context.Context, arg InsertExecutionParams) error {
|
|
_, err := q.db.Exec(ctx, insertExecution,
|
|
arg.EntityID,
|
|
arg.ClassificationID,
|
|
arg.SignalEntityID,
|
|
arg.TargetEntityID,
|
|
arg.Action,
|
|
arg.RiskClass,
|
|
arg.ApprovalID,
|
|
arg.AgentID,
|
|
arg.SkillID,
|
|
arg.SkillVersion,
|
|
arg.CorrelationID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertFeedback = `-- name: InsertFeedback :exec
|
|
INSERT INTO feedback (entity_id, execution_id, outcome, observation, lesson,
|
|
unexpected_side_effects, tags)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
`
|
|
|
|
type InsertFeedbackParams struct {
|
|
EntityID uuid.UUID
|
|
ExecutionID uuid.UUID
|
|
Outcome string
|
|
Observation *string
|
|
Lesson *string
|
|
UnexpectedSideEffects []string
|
|
Tags []string
|
|
}
|
|
|
|
func (q *Queries) InsertFeedback(ctx context.Context, arg InsertFeedbackParams) error {
|
|
_, err := q.db.Exec(ctx, insertFeedback,
|
|
arg.EntityID,
|
|
arg.ExecutionID,
|
|
arg.Outcome,
|
|
arg.Observation,
|
|
arg.Lesson,
|
|
arg.UnexpectedSideEffects,
|
|
arg.Tags,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertMetricSample = `-- name: InsertMetricSample :exec
|
|
INSERT INTO metric_samples (entity_id, metric, value, tags, ts)
|
|
VALUES ($1, $2, $3, $4, now())
|
|
`
|
|
|
|
type InsertMetricSampleParams struct {
|
|
EntityID uuid.UUID
|
|
Metric string
|
|
Value float64
|
|
Tags []byte
|
|
}
|
|
|
|
func (q *Queries) InsertMetricSample(ctx context.Context, arg InsertMetricSampleParams) error {
|
|
_, err := q.db.Exec(ctx, insertMetricSample,
|
|
arg.EntityID,
|
|
arg.Metric,
|
|
arg.Value,
|
|
arg.Tags,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertSkill = `-- name: InsertSkill :exec
|
|
INSERT INTO skills (entity_id, version, name, procedure, applies_type, action,
|
|
pattern_ids, status, changed_by, change_reason)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
`
|
|
|
|
type InsertSkillParams struct {
|
|
EntityID uuid.UUID
|
|
Version int32
|
|
Name string
|
|
Procedure []byte
|
|
AppliesType *string
|
|
Action string
|
|
PatternIds []uuid.UUID
|
|
Status string
|
|
ChangedBy *uuid.UUID
|
|
ChangeReason *string
|
|
}
|
|
|
|
func (q *Queries) InsertSkill(ctx context.Context, arg InsertSkillParams) error {
|
|
_, err := q.db.Exec(ctx, insertSkill,
|
|
arg.EntityID,
|
|
arg.Version,
|
|
arg.Name,
|
|
arg.Procedure,
|
|
arg.AppliesType,
|
|
arg.Action,
|
|
arg.PatternIds,
|
|
arg.Status,
|
|
arg.ChangedBy,
|
|
arg.ChangeReason,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const listApprovalRules = `-- name: ListApprovalRules :many
|
|
SELECT id, entity_type, action, risk_class, autonomy_level, scope_entity, version, updated_at FROM approval_rules ORDER BY entity_type, action
|
|
`
|
|
|
|
func (q *Queries) ListApprovalRules(ctx context.Context) ([]ApprovalRule, error) {
|
|
rows, err := q.db.Query(ctx, listApprovalRules)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ApprovalRule
|
|
for rows.Next() {
|
|
var i ApprovalRule
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.EntityType,
|
|
&i.Action,
|
|
&i.RiskClass,
|
|
&i.AutonomyLevel,
|
|
&i.ScopeEntity,
|
|
&i.Version,
|
|
&i.UpdatedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listApprovals = `-- name: ListApprovals :many
|
|
SELECT a.entity_id, a.subject_entity_id, a.action, a.risk_class, a.kind, a.payload, a.status, a.token_hash, a.expires_at, a.decided_at, a.decided_by, a.created_at, a.matrix_event_id, a.alert_sent_at, e.slug AS subject_slug
|
|
FROM approvals a
|
|
JOIN entities e ON e.id = a.subject_entity_id
|
|
WHERE ($1::text IS NULL OR a.status = $1)
|
|
AND ($2::text IS NULL OR e.slug > $2)
|
|
ORDER BY e.slug
|
|
LIMIT $3
|
|
`
|
|
|
|
type ListApprovalsParams struct {
|
|
Status *string
|
|
Cursor *string
|
|
Lim int32
|
|
}
|
|
|
|
type ListApprovalsRow struct {
|
|
EntityID uuid.UUID
|
|
SubjectEntityID *uuid.UUID
|
|
Action string
|
|
RiskClass string
|
|
Kind string
|
|
Payload []byte
|
|
Status string
|
|
TokenHash *string
|
|
ExpiresAt time.Time
|
|
DecidedAt *time.Time
|
|
DecidedBy *uuid.UUID
|
|
CreatedAt time.Time
|
|
MatrixEventID *string
|
|
AlertSentAt *time.Time
|
|
SubjectSlug string
|
|
}
|
|
|
|
func (q *Queries) ListApprovals(ctx context.Context, arg ListApprovalsParams) ([]ListApprovalsRow, error) {
|
|
rows, err := q.db.Query(ctx, listApprovals, arg.Status, arg.Cursor, arg.Lim)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListApprovalsRow
|
|
for rows.Next() {
|
|
var i ListApprovalsRow
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.SubjectEntityID,
|
|
&i.Action,
|
|
&i.RiskClass,
|
|
&i.Kind,
|
|
&i.Payload,
|
|
&i.Status,
|
|
&i.TokenHash,
|
|
&i.ExpiresAt,
|
|
&i.DecidedAt,
|
|
&i.DecidedBy,
|
|
&i.CreatedAt,
|
|
&i.MatrixEventID,
|
|
&i.AlertSentAt,
|
|
&i.SubjectSlug,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listClassifications = `-- name: ListClassifications :many
|
|
SELECT c.entity_id, c.signal_entity_id, c.target_entity_id, c.action,
|
|
c.recommended_action, c.risk_class, c.route, c.blast_radius,
|
|
c.pattern_confidence, c.skill_id, c.autonomy_check, c.reasoning,
|
|
c.correlation_id, c.created_at,
|
|
e.slug AS target_slug
|
|
FROM classifications c
|
|
JOIN entities e ON e.id = c.target_entity_id
|
|
WHERE ($1::text IS NULL OR c.route = $1)
|
|
AND ($2::text IS NULL OR e.slug > $2)
|
|
ORDER BY e.slug
|
|
LIMIT $3
|
|
`
|
|
|
|
type ListClassificationsParams struct {
|
|
Route *string
|
|
Cursor *string
|
|
Lim int32
|
|
}
|
|
|
|
type ListClassificationsRow struct {
|
|
EntityID uuid.UUID
|
|
SignalEntityID *uuid.UUID
|
|
TargetEntityID *uuid.UUID
|
|
Action string
|
|
RecommendedAction []byte
|
|
RiskClass string
|
|
Route string
|
|
BlastRadius []uuid.UUID
|
|
PatternConfidence *float32
|
|
SkillID *uuid.UUID
|
|
AutonomyCheck *string
|
|
Reasoning []byte
|
|
CorrelationID string
|
|
CreatedAt time.Time
|
|
TargetSlug string
|
|
}
|
|
|
|
func (q *Queries) ListClassifications(ctx context.Context, arg ListClassificationsParams) ([]ListClassificationsRow, error) {
|
|
rows, err := q.db.Query(ctx, listClassifications, arg.Route, arg.Cursor, arg.Lim)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListClassificationsRow
|
|
for rows.Next() {
|
|
var i ListClassificationsRow
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.SignalEntityID,
|
|
&i.TargetEntityID,
|
|
&i.Action,
|
|
&i.RecommendedAction,
|
|
&i.RiskClass,
|
|
&i.Route,
|
|
&i.BlastRadius,
|
|
&i.PatternConfidence,
|
|
&i.SkillID,
|
|
&i.AutonomyCheck,
|
|
&i.Reasoning,
|
|
&i.CorrelationID,
|
|
&i.CreatedAt,
|
|
&i.TargetSlug,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listEnabledCheckDefs = `-- name: ListEnabledCheckDefs :many
|
|
|
|
SELECT cd.entity_id, cd.target_id, cd.target_type, cd.kind, cd.config,
|
|
cd.interval_s, cd.timeout_s, cd.zone, cd.enabled, cd.updated_at,
|
|
e.slug AS entity_slug
|
|
FROM check_defs cd
|
|
JOIN entities e ON e.id = cd.entity_id
|
|
WHERE cd.enabled = true
|
|
`
|
|
|
|
type ListEnabledCheckDefsRow struct {
|
|
EntityID uuid.UUID
|
|
TargetID *uuid.UUID
|
|
TargetType *string
|
|
Kind string
|
|
Config []byte
|
|
IntervalS int32
|
|
TimeoutS int32
|
|
Zone *string
|
|
Enabled bool
|
|
UpdatedAt time.Time
|
|
EntitySlug string
|
|
}
|
|
|
|
// =====================================================================
|
|
// Phase 3 queries
|
|
// =====================================================================
|
|
func (q *Queries) ListEnabledCheckDefs(ctx context.Context) ([]ListEnabledCheckDefsRow, error) {
|
|
rows, err := q.db.Query(ctx, listEnabledCheckDefs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListEnabledCheckDefsRow
|
|
for rows.Next() {
|
|
var i ListEnabledCheckDefsRow
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.TargetID,
|
|
&i.TargetType,
|
|
&i.Kind,
|
|
&i.Config,
|
|
&i.IntervalS,
|
|
&i.TimeoutS,
|
|
&i.Zone,
|
|
&i.Enabled,
|
|
&i.UpdatedAt,
|
|
&i.EntitySlug,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listEntityStatus = `-- name: ListEntityStatus :many
|
|
SELECT e.slug, e.type, st.health, st.last_check_at
|
|
FROM entity_status st JOIN entities e ON e.id = st.entity_id
|
|
ORDER BY e.slug
|
|
`
|
|
|
|
type ListEntityStatusRow struct {
|
|
Slug string
|
|
Type string
|
|
Health string
|
|
LastCheckAt *time.Time
|
|
}
|
|
|
|
func (q *Queries) ListEntityStatus(ctx context.Context) ([]ListEntityStatusRow, error) {
|
|
rows, err := q.db.Query(ctx, listEntityStatus)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListEntityStatusRow
|
|
for rows.Next() {
|
|
var i ListEntityStatusRow
|
|
if err := rows.Scan(
|
|
&i.Slug,
|
|
&i.Type,
|
|
&i.Health,
|
|
&i.LastCheckAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listEvents = `-- name: ListEvents :many
|
|
SELECT id, ts, type, entity_id, severity, source, data, correlation_id
|
|
FROM events
|
|
WHERE ($1::text IS NULL OR type = $1)
|
|
AND ($2::uuid IS NULL OR entity_id = $2)
|
|
AND ($3::text IS NULL OR severity = $3)
|
|
AND ($4::text IS NULL OR correlation_id = $4)
|
|
AND ($5::timestamptz IS NULL OR ts >= $5)
|
|
AND ($6::timestamptz IS NULL OR ts <= $6)
|
|
AND ($7::bigint IS NULL OR id < $7)
|
|
ORDER BY id DESC
|
|
LIMIT $8
|
|
`
|
|
|
|
type ListEventsParams struct {
|
|
Type *string
|
|
EntityID *uuid.UUID
|
|
Severity *string
|
|
CorrelationID *string
|
|
FromTs *time.Time
|
|
ToTs *time.Time
|
|
BeforeID *int64
|
|
Lim int32
|
|
}
|
|
|
|
func (q *Queries) ListEvents(ctx context.Context, arg ListEventsParams) ([]Event, error) {
|
|
rows, err := q.db.Query(ctx, listEvents,
|
|
arg.Type,
|
|
arg.EntityID,
|
|
arg.Severity,
|
|
arg.CorrelationID,
|
|
arg.FromTs,
|
|
arg.ToTs,
|
|
arg.BeforeID,
|
|
arg.Lim,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Event
|
|
for rows.Next() {
|
|
var i Event
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.Ts,
|
|
&i.Type,
|
|
&i.EntityID,
|
|
&i.Severity,
|
|
&i.Source,
|
|
&i.Data,
|
|
&i.CorrelationID,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listEventsAfter = `-- name: ListEventsAfter :many
|
|
SELECT id, ts, type, entity_id, severity, source, data, correlation_id
|
|
FROM events WHERE id > $1 ORDER BY id ASC LIMIT $2
|
|
`
|
|
|
|
type ListEventsAfterParams struct {
|
|
ID int64
|
|
Limit int32
|
|
}
|
|
|
|
func (q *Queries) ListEventsAfter(ctx context.Context, arg ListEventsAfterParams) ([]Event, error) {
|
|
rows, err := q.db.Query(ctx, listEventsAfter, arg.ID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Event
|
|
for rows.Next() {
|
|
var i Event
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.Ts,
|
|
&i.Type,
|
|
&i.EntityID,
|
|
&i.Severity,
|
|
&i.Source,
|
|
&i.Data,
|
|
&i.CorrelationID,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listExecutions = `-- name: ListExecutions :many
|
|
SELECT e.entity_id, e.classification_id, e.signal_entity_id, e.target_entity_id,
|
|
e.action, e.risk_class, e.approval_id, e.agent_id,
|
|
e.skill_id, e.skill_version, e.status, e.result, e.duration_ms,
|
|
e.verified, e.correlation_id, e.started_at, e.completed_at, e.created_at,
|
|
te.slug AS target_slug
|
|
FROM executions e
|
|
JOIN entities te ON te.id = e.target_entity_id
|
|
WHERE ($1::text IS NULL OR e.status = $1)
|
|
AND ($2::text IS NULL OR te.slug > $2)
|
|
ORDER BY te.slug
|
|
LIMIT $3
|
|
`
|
|
|
|
type ListExecutionsParams struct {
|
|
Status *string
|
|
Cursor *string
|
|
Lim int32
|
|
}
|
|
|
|
type ListExecutionsRow struct {
|
|
EntityID uuid.UUID
|
|
ClassificationID *uuid.UUID
|
|
SignalEntityID *uuid.UUID
|
|
TargetEntityID *uuid.UUID
|
|
Action string
|
|
RiskClass string
|
|
ApprovalID *uuid.UUID
|
|
AgentID *uuid.UUID
|
|
SkillID *uuid.UUID
|
|
SkillVersion *int32
|
|
Status string
|
|
Result []byte
|
|
DurationMs *int32
|
|
Verified bool
|
|
CorrelationID string
|
|
StartedAt *time.Time
|
|
CompletedAt *time.Time
|
|
CreatedAt time.Time
|
|
TargetSlug string
|
|
}
|
|
|
|
func (q *Queries) ListExecutions(ctx context.Context, arg ListExecutionsParams) ([]ListExecutionsRow, error) {
|
|
rows, err := q.db.Query(ctx, listExecutions, arg.Status, arg.Cursor, arg.Lim)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListExecutionsRow
|
|
for rows.Next() {
|
|
var i ListExecutionsRow
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.ClassificationID,
|
|
&i.SignalEntityID,
|
|
&i.TargetEntityID,
|
|
&i.Action,
|
|
&i.RiskClass,
|
|
&i.ApprovalID,
|
|
&i.AgentID,
|
|
&i.SkillID,
|
|
&i.SkillVersion,
|
|
&i.Status,
|
|
&i.Result,
|
|
&i.DurationMs,
|
|
&i.Verified,
|
|
&i.CorrelationID,
|
|
&i.StartedAt,
|
|
&i.CompletedAt,
|
|
&i.CreatedAt,
|
|
&i.TargetSlug,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listPatterns = `-- name: ListPatterns :many
|
|
SELECT p.entity_id, p.applies_type, p.action, p.pattern, p.confidence, p.evidence_count, p.success_count, p.failure_count, p.status, p.quarantined, p.version, p.last_validated_at, p.created_at FROM patterns p
|
|
WHERE ($1::text IS NULL OR p.status = $1)
|
|
ORDER BY p.applies_type, p.action
|
|
`
|
|
|
|
func (q *Queries) ListPatterns(ctx context.Context, status *string) ([]Pattern, error) {
|
|
rows, err := q.db.Query(ctx, listPatterns, status)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Pattern
|
|
for rows.Next() {
|
|
var i Pattern
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.AppliesType,
|
|
&i.Action,
|
|
&i.Pattern,
|
|
&i.Confidence,
|
|
&i.EvidenceCount,
|
|
&i.SuccessCount,
|
|
&i.FailureCount,
|
|
&i.Status,
|
|
&i.Quarantined,
|
|
&i.Version,
|
|
&i.LastValidatedAt,
|
|
&i.CreatedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listRiskClasses = `-- name: ListRiskClasses :many
|
|
SELECT name, description, approval_required, autonomy_allowed FROM risk_classes ORDER BY name
|
|
`
|
|
|
|
func (q *Queries) ListRiskClasses(ctx context.Context) ([]RiskClass, error) {
|
|
rows, err := q.db.Query(ctx, listRiskClasses)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []RiskClass
|
|
for rows.Next() {
|
|
var i RiskClass
|
|
if err := rows.Scan(
|
|
&i.Name,
|
|
&i.Description,
|
|
&i.ApprovalRequired,
|
|
&i.AutonomyAllowed,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listSignals = `-- name: ListSignals :many
|
|
SELECT sig.entity_id, se.slug, sig.kind, sig.severity, sig.state,
|
|
te.slug AS target_slug, sig.check_id, sig.evidence, sig.likely_cause,
|
|
sig.occurrence_count, sig.flap_count, sig.hold_down_until,
|
|
sig.mute_until, sig.first_seen_at, sig.last_seen_at
|
|
FROM signals sig
|
|
JOIN entities se ON se.id = sig.entity_id
|
|
LEFT JOIN entities te ON te.id = sig.target_entity_id
|
|
WHERE ($1::text IS NULL OR sig.state = $1)
|
|
AND ($2::text IS NULL OR sig.severity = $2)
|
|
AND ($3::text IS NULL OR te.slug = $3)
|
|
AND ($4::text IS NULL OR sig.kind = $4)
|
|
AND ($5::text IS NULL OR se.slug > $5)
|
|
ORDER BY se.slug
|
|
LIMIT $6
|
|
`
|
|
|
|
type ListSignalsParams struct {
|
|
State *string
|
|
Severity *string
|
|
Target *string
|
|
Kind *string
|
|
Cursor *string
|
|
Lim int32
|
|
}
|
|
|
|
type ListSignalsRow struct {
|
|
EntityID uuid.UUID
|
|
Slug string
|
|
Kind string
|
|
Severity string
|
|
State string
|
|
TargetSlug *string
|
|
CheckID *uuid.UUID
|
|
Evidence *string
|
|
LikelyCause *string
|
|
OccurrenceCount int32
|
|
FlapCount int32
|
|
HoldDownUntil *time.Time
|
|
MuteUntil *time.Time
|
|
FirstSeenAt time.Time
|
|
LastSeenAt time.Time
|
|
}
|
|
|
|
func (q *Queries) ListSignals(ctx context.Context, arg ListSignalsParams) ([]ListSignalsRow, error) {
|
|
rows, err := q.db.Query(ctx, listSignals,
|
|
arg.State,
|
|
arg.Severity,
|
|
arg.Target,
|
|
arg.Kind,
|
|
arg.Cursor,
|
|
arg.Lim,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListSignalsRow
|
|
for rows.Next() {
|
|
var i ListSignalsRow
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.Slug,
|
|
&i.Kind,
|
|
&i.Severity,
|
|
&i.State,
|
|
&i.TargetSlug,
|
|
&i.CheckID,
|
|
&i.Evidence,
|
|
&i.LikelyCause,
|
|
&i.OccurrenceCount,
|
|
&i.FlapCount,
|
|
&i.HoldDownUntil,
|
|
&i.MuteUntil,
|
|
&i.FirstSeenAt,
|
|
&i.LastSeenAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listSkills = `-- name: ListSkills :many
|
|
SELECT entity_id, version, name, procedure, applies_type, action, pattern_ids, status, success_rate, changed_by, change_reason, last_used_at, created_at FROM skills
|
|
WHERE ($1::text IS NULL OR status = $1)
|
|
ORDER BY name, version DESC
|
|
`
|
|
|
|
func (q *Queries) ListSkills(ctx context.Context, status *string) ([]Skill, error) {
|
|
rows, err := q.db.Query(ctx, listSkills, status)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Skill
|
|
for rows.Next() {
|
|
var i Skill
|
|
if err := rows.Scan(
|
|
&i.EntityID,
|
|
&i.Version,
|
|
&i.Name,
|
|
&i.Procedure,
|
|
&i.AppliesType,
|
|
&i.Action,
|
|
&i.PatternIds,
|
|
&i.Status,
|
|
&i.SuccessRate,
|
|
&i.ChangedBy,
|
|
&i.ChangeReason,
|
|
&i.LastUsedAt,
|
|
&i.CreatedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const putIdempotentResponse = `-- name: PutIdempotentResponse :exec
|
|
INSERT INTO idempotency_keys (actor, key, request_hash, response_code, response_body)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
ON CONFLICT (actor, key) DO NOTHING
|
|
`
|
|
|
|
type PutIdempotentResponseParams struct {
|
|
Actor string
|
|
Key string
|
|
RequestHash string
|
|
ResponseCode *int32
|
|
ResponseBody []byte
|
|
}
|
|
|
|
func (q *Queries) PutIdempotentResponse(ctx context.Context, arg PutIdempotentResponseParams) error {
|
|
_, err := q.db.Exec(ctx, putIdempotentResponse,
|
|
arg.Actor,
|
|
arg.Key,
|
|
arg.RequestHash,
|
|
arg.ResponseCode,
|
|
arg.ResponseBody,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const queryMetrics = `-- name: QueryMetrics :many
|
|
SELECT time_bucket($4::interval, ts) AS bucket,
|
|
entity_id, metric,
|
|
ROUND(avg(value)::numeric, 2) AS avg_val,
|
|
ROUND(min(value)::numeric, 2) AS min_val,
|
|
ROUND(max(value)::numeric, 2) AS max_val
|
|
FROM metric_samples
|
|
WHERE entity_id = $1
|
|
AND metric = $2
|
|
AND ts > $3
|
|
GROUP BY bucket, entity_id, metric
|
|
ORDER BY bucket DESC
|
|
`
|
|
|
|
type QueryMetricsParams struct {
|
|
EntityID uuid.UUID
|
|
Metric string
|
|
Ts time.Time
|
|
BucketInterval pgtype.Interval
|
|
}
|
|
|
|
type QueryMetricsRow struct {
|
|
Bucket interface{}
|
|
EntityID uuid.UUID
|
|
Metric string
|
|
AvgVal pgtype.Numeric
|
|
MinVal pgtype.Numeric
|
|
MaxVal pgtype.Numeric
|
|
}
|
|
|
|
func (q *Queries) QueryMetrics(ctx context.Context, arg QueryMetricsParams) ([]QueryMetricsRow, error) {
|
|
rows, err := q.db.Query(ctx, queryMetrics,
|
|
arg.EntityID,
|
|
arg.Metric,
|
|
arg.Ts,
|
|
arg.BucketInterval,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []QueryMetricsRow
|
|
for rows.Next() {
|
|
var i QueryMetricsRow
|
|
if err := rows.Scan(
|
|
&i.Bucket,
|
|
&i.EntityID,
|
|
&i.Metric,
|
|
&i.AvgVal,
|
|
&i.MinVal,
|
|
&i.MaxVal,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const updateApprovalStatus = `-- name: UpdateApprovalStatus :exec
|
|
UPDATE approvals SET status = $2, decided_at = now(), decided_by = $3
|
|
WHERE entity_id = $1 AND status = 'pending'
|
|
`
|
|
|
|
type UpdateApprovalStatusParams struct {
|
|
EntityID uuid.UUID
|
|
Status string
|
|
DecidedBy *uuid.UUID
|
|
}
|
|
|
|
func (q *Queries) UpdateApprovalStatus(ctx context.Context, arg UpdateApprovalStatusParams) error {
|
|
_, err := q.db.Exec(ctx, updateApprovalStatus, arg.EntityID, arg.Status, arg.DecidedBy)
|
|
return err
|
|
}
|
|
|
|
const updateCheckDef = `-- name: UpdateCheckDef :exec
|
|
UPDATE check_defs SET kind = $2, config = $3, interval_s = $4, timeout_s = $5,
|
|
target_id = $6, target_type = $7, zone = $8, enabled = $9, updated_at = now()
|
|
WHERE entity_id = $1
|
|
`
|
|
|
|
type UpdateCheckDefParams struct {
|
|
EntityID uuid.UUID
|
|
Kind string
|
|
Config []byte
|
|
IntervalS int32
|
|
TimeoutS int32
|
|
TargetID *uuid.UUID
|
|
TargetType *string
|
|
Zone *string
|
|
Enabled bool
|
|
}
|
|
|
|
func (q *Queries) UpdateCheckDef(ctx context.Context, arg UpdateCheckDefParams) error {
|
|
_, err := q.db.Exec(ctx, updateCheckDef,
|
|
arg.EntityID,
|
|
arg.Kind,
|
|
arg.Config,
|
|
arg.IntervalS,
|
|
arg.TimeoutS,
|
|
arg.TargetID,
|
|
arg.TargetType,
|
|
arg.Zone,
|
|
arg.Enabled,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const updateExecutionStatus = `-- name: UpdateExecutionStatus :exec
|
|
UPDATE executions SET status = $2, result = $3, duration_ms = $4,
|
|
verified = $5, started_at = COALESCE(started_at, now()),
|
|
completed_at = CASE WHEN $2 IN ('completed','failed','cancelled') THEN now() ELSE completed_at END
|
|
WHERE entity_id = $1
|
|
`
|
|
|
|
type UpdateExecutionStatusParams struct {
|
|
EntityID uuid.UUID
|
|
Status string
|
|
Result []byte
|
|
DurationMs *int32
|
|
Verified bool
|
|
}
|
|
|
|
func (q *Queries) UpdateExecutionStatus(ctx context.Context, arg UpdateExecutionStatusParams) error {
|
|
_, err := q.db.Exec(ctx, updateExecutionStatus,
|
|
arg.EntityID,
|
|
arg.Status,
|
|
arg.Result,
|
|
arg.DurationMs,
|
|
arg.Verified,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const updatePatternQuarantine = `-- name: UpdatePatternQuarantine :exec
|
|
UPDATE patterns SET quarantined = $2 WHERE entity_id = $1
|
|
`
|
|
|
|
type UpdatePatternQuarantineParams struct {
|
|
EntityID uuid.UUID
|
|
Quarantined bool
|
|
}
|
|
|
|
func (q *Queries) UpdatePatternQuarantine(ctx context.Context, arg UpdatePatternQuarantineParams) error {
|
|
_, err := q.db.Exec(ctx, updatePatternQuarantine, arg.EntityID, arg.Quarantined)
|
|
return err
|
|
}
|
|
|
|
const updatePatternStatus = `-- name: UpdatePatternStatus :exec
|
|
UPDATE patterns SET status = $2, version = version + 1,
|
|
last_validated_at = CASE WHEN $2 = 'validated' THEN now() ELSE last_validated_at END
|
|
WHERE entity_id = $1
|
|
`
|
|
|
|
type UpdatePatternStatusParams struct {
|
|
EntityID uuid.UUID
|
|
Status string
|
|
}
|
|
|
|
func (q *Queries) UpdatePatternStatus(ctx context.Context, arg UpdatePatternStatusParams) error {
|
|
_, err := q.db.Exec(ctx, updatePatternStatus, arg.EntityID, arg.Status)
|
|
return err
|
|
}
|
|
|
|
const updateSignalState = `-- name: UpdateSignalState :exec
|
|
UPDATE signals SET state = $2, updated_at = now() WHERE entity_id = $1
|
|
`
|
|
|
|
type UpdateSignalStateParams struct {
|
|
EntityID uuid.UUID
|
|
State string
|
|
}
|
|
|
|
func (q *Queries) UpdateSignalState(ctx context.Context, arg UpdateSignalStateParams) error {
|
|
_, err := q.db.Exec(ctx, updateSignalState, arg.EntityID, arg.State)
|
|
return err
|
|
}
|
|
|
|
const updateSkillStatus = `-- name: UpdateSkillStatus :exec
|
|
UPDATE skills SET status = $2, last_used_at = now() WHERE entity_id = $1 AND version = $2
|
|
`
|
|
|
|
type UpdateSkillStatusParams struct {
|
|
EntityID uuid.UUID
|
|
Status string
|
|
}
|
|
|
|
func (q *Queries) UpdateSkillStatus(ctx context.Context, arg UpdateSkillStatusParams) error {
|
|
_, err := q.db.Exec(ctx, updateSkillStatus, arg.EntityID, arg.Status)
|
|
return err
|
|
}
|
|
|
|
const upsertEntityStatus = `-- name: UpsertEntityStatus :exec
|
|
INSERT INTO entity_status (entity_id, health, last_check_at, details)
|
|
VALUES ($1, $2, $3, $4)
|
|
ON CONFLICT (entity_id)
|
|
DO UPDATE SET health = EXCLUDED.health,
|
|
last_check_at = EXCLUDED.last_check_at,
|
|
details = EXCLUDED.details,
|
|
updated_at = now()
|
|
`
|
|
|
|
type UpsertEntityStatusParams struct {
|
|
EntityID uuid.UUID
|
|
Health string
|
|
LastCheckAt *time.Time
|
|
Details []byte
|
|
}
|
|
|
|
func (q *Queries) UpsertEntityStatus(ctx context.Context, arg UpsertEntityStatusParams) error {
|
|
_, err := q.db.Exec(ctx, upsertEntityStatus,
|
|
arg.EntityID,
|
|
arg.Health,
|
|
arg.LastCheckAt,
|
|
arg.Details,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const upsertPattern = `-- name: UpsertPattern :exec
|
|
INSERT INTO patterns (entity_id, applies_type, action, pattern, confidence,
|
|
evidence_count, success_count, failure_count, status, version)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'hypothesized', 1)
|
|
ON CONFLICT (applies_type, action)
|
|
DO UPDATE SET evidence_count = patterns.evidence_count + EXCLUDED.evidence_count,
|
|
success_count = patterns.success_count + EXCLUDED.success_count,
|
|
failure_count = patterns.failure_count + EXCLUDED.failure_count,
|
|
updated_at = now()
|
|
`
|
|
|
|
type UpsertPatternParams struct {
|
|
EntityID uuid.UUID
|
|
AppliesType string
|
|
Action string
|
|
Pattern string
|
|
Confidence float32
|
|
EvidenceCount int32
|
|
SuccessCount int32
|
|
FailureCount int32
|
|
}
|
|
|
|
func (q *Queries) UpsertPattern(ctx context.Context, arg UpsertPatternParams) error {
|
|
_, err := q.db.Exec(ctx, upsertPattern,
|
|
arg.EntityID,
|
|
arg.AppliesType,
|
|
arg.Action,
|
|
arg.Pattern,
|
|
arg.Confidence,
|
|
arg.EvidenceCount,
|
|
arg.SuccessCount,
|
|
arg.FailureCount,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const upsertSignal = `-- name: UpsertSignal :one
|
|
INSERT INTO signals (entity_id, kind, severity, target_entity_id, check_id, evidence, likely_cause, state)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, 'raised')
|
|
ON CONFLICT (target_entity_id, kind) WHERE state NOT IN ('resolved','failed')
|
|
DO UPDATE SET occurrence_count = signals.occurrence_count + 1,
|
|
last_seen_at = now(),
|
|
evidence = EXCLUDED.evidence,
|
|
updated_at = now()
|
|
RETURNING entity_id, kind, severity, target_entity_id, check_id, evidence, likely_cause, state, occurrence_count, first_seen_at, last_seen_at, flap_count, hold_down_until, mute_until, created_at, updated_at
|
|
`
|
|
|
|
type UpsertSignalParams struct {
|
|
EntityID uuid.UUID
|
|
Kind string
|
|
Severity string
|
|
TargetEntityID *uuid.UUID
|
|
CheckID *uuid.UUID
|
|
Evidence *string
|
|
LikelyCause *string
|
|
}
|
|
|
|
func (q *Queries) UpsertSignal(ctx context.Context, arg UpsertSignalParams) (Signal, error) {
|
|
row := q.db.QueryRow(ctx, upsertSignal,
|
|
arg.EntityID,
|
|
arg.Kind,
|
|
arg.Severity,
|
|
arg.TargetEntityID,
|
|
arg.CheckID,
|
|
arg.Evidence,
|
|
arg.LikelyCause,
|
|
)
|
|
var i Signal
|
|
err := row.Scan(
|
|
&i.EntityID,
|
|
&i.Kind,
|
|
&i.Severity,
|
|
&i.TargetEntityID,
|
|
&i.CheckID,
|
|
&i.Evidence,
|
|
&i.LikelyCause,
|
|
&i.State,
|
|
&i.OccurrenceCount,
|
|
&i.FirstSeenAt,
|
|
&i.LastSeenAt,
|
|
&i.FlapCount,
|
|
&i.HoldDownUntil,
|
|
&i.MuteUntil,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|