Files
Containr/app/backend/internal/database/sqlcdb/webhooks.sql.go
T
Tomas Dvorak f499678964 feat: outbound webhooks — signed event delivery + delivery log
Every audited action now emits a "resource.action" event (bare actions
get resource-qualified; already-qualified actions like service.clone
pass through). Webhooks subscribe per-user with exact names, resource.*
wildcards, or *.

- schema: outbound_webhooks + webhook_deliveries (sqlc + goose)
- dispatcher: 4 workers, 512-queue, 3 attempts with backoff, 10s timeout;
  deliveries record status/http-code/body(4KiB)/duration
- signing: X-Containr-Signature sha256=<hmac> over raw body;
  X-Containr-Event + X-Containr-Delivery headers; custom headers per hook
- api: CRUD + /deliveries + /test (ping) under authed group
- fix: SetAuditDB never called — LogAudit was a silent no-op at every
  call site; now wired at boot
- coverage: service create/delete audited (previously uninstrumented)
- cli: containr webhooks list|create|update|delete|deliveries|test
- mcp: 6 tools, delete requires confirm
- frontend: /settings/webhooks page — list/create/expand-deliveries/
  test/disable/delete, secret-shown-once banner; nav + account menu
- openapi + regenerated types; CLI.md + docs snapshot; roadmap ticks
2026-10-09 09:44:08 +02:00

330 lines
9.4 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: webhooks.sql
package sqlcdb
import (
"context"
"database/sql"
"encoding/json"
"github.com/google/uuid"
"github.com/sqlc-dev/pqtype"
)
const createOutboundWebhook = `-- name: CreateOutboundWebhook :exec
INSERT INTO outbound_webhooks (id, user_id, name, url, secret, events, headers, enabled, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
`
type CreateOutboundWebhookParams struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
Name string `json:"name"`
Url string `json:"url"`
Secret string `json:"secret"`
Events json.RawMessage `json:"events"`
Headers pqtype.NullRawMessage `json:"headers"`
Enabled bool `json:"enabled"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
}
func (q *Queries) CreateOutboundWebhook(ctx context.Context, arg CreateOutboundWebhookParams) error {
_, err := q.db.ExecContext(ctx, createOutboundWebhook,
arg.ID,
arg.UserID,
arg.Name,
arg.Url,
arg.Secret,
arg.Events,
arg.Headers,
arg.Enabled,
arg.CreatedAt,
arg.UpdatedAt,
)
return err
}
const createWebhookDelivery = `-- name: CreateWebhookDelivery :exec
INSERT INTO webhook_deliveries (id, webhook_id, event, payload, status, created_at)
VALUES ($1, $2, $3, $4, $5, $6)
`
type CreateWebhookDeliveryParams struct {
ID uuid.UUID `json:"id"`
WebhookID uuid.UUID `json:"webhook_id"`
Event string `json:"event"`
Payload pqtype.NullRawMessage `json:"payload"`
Status string `json:"status"`
CreatedAt sql.NullTime `json:"created_at"`
}
func (q *Queries) CreateWebhookDelivery(ctx context.Context, arg CreateWebhookDeliveryParams) error {
_, err := q.db.ExecContext(ctx, createWebhookDelivery,
arg.ID,
arg.WebhookID,
arg.Event,
arg.Payload,
arg.Status,
arg.CreatedAt,
)
return err
}
const deleteOutboundWebhookByIDAndUser = `-- name: DeleteOutboundWebhookByIDAndUser :exec
DELETE FROM outbound_webhooks
WHERE id = $1 AND user_id = $2
`
type DeleteOutboundWebhookByIDAndUserParams struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
}
func (q *Queries) DeleteOutboundWebhookByIDAndUser(ctx context.Context, arg DeleteOutboundWebhookByIDAndUserParams) error {
_, err := q.db.ExecContext(ctx, deleteOutboundWebhookByIDAndUser, arg.ID, arg.UserID)
return err
}
const getOutboundWebhookByID = `-- name: GetOutboundWebhookByID :one
SELECT outbound_webhooks.id, outbound_webhooks.user_id, outbound_webhooks.name, outbound_webhooks.url, outbound_webhooks.secret, outbound_webhooks.events, outbound_webhooks.headers, outbound_webhooks.enabled, outbound_webhooks.created_at, outbound_webhooks.updated_at
FROM outbound_webhooks
WHERE id = $1
`
func (q *Queries) GetOutboundWebhookByID(ctx context.Context, id uuid.UUID) (OutboundWebhook, error) {
row := q.db.QueryRowContext(ctx, getOutboundWebhookByID, id)
var i OutboundWebhook
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Url,
&i.Secret,
&i.Events,
&i.Headers,
&i.Enabled,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getOutboundWebhookByIDAndUser = `-- name: GetOutboundWebhookByIDAndUser :one
SELECT outbound_webhooks.id, outbound_webhooks.user_id, outbound_webhooks.name, outbound_webhooks.url, outbound_webhooks.secret, outbound_webhooks.events, outbound_webhooks.headers, outbound_webhooks.enabled, outbound_webhooks.created_at, outbound_webhooks.updated_at
FROM outbound_webhooks
WHERE id = $1 AND user_id = $2
`
type GetOutboundWebhookByIDAndUserParams struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
}
func (q *Queries) GetOutboundWebhookByIDAndUser(ctx context.Context, arg GetOutboundWebhookByIDAndUserParams) (OutboundWebhook, error) {
row := q.db.QueryRowContext(ctx, getOutboundWebhookByIDAndUser, arg.ID, arg.UserID)
var i OutboundWebhook
err := row.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Url,
&i.Secret,
&i.Events,
&i.Headers,
&i.Enabled,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const listEnabledOutboundWebhooks = `-- name: ListEnabledOutboundWebhooks :many
SELECT outbound_webhooks.id, outbound_webhooks.user_id, outbound_webhooks.name, outbound_webhooks.url, outbound_webhooks.secret, outbound_webhooks.events, outbound_webhooks.headers, outbound_webhooks.enabled, outbound_webhooks.created_at, outbound_webhooks.updated_at
FROM outbound_webhooks
WHERE enabled
`
func (q *Queries) ListEnabledOutboundWebhooks(ctx context.Context) ([]OutboundWebhook, error) {
rows, err := q.db.QueryContext(ctx, listEnabledOutboundWebhooks)
if err != nil {
return nil, err
}
defer rows.Close()
items := []OutboundWebhook{}
for rows.Next() {
var i OutboundWebhook
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Url,
&i.Secret,
&i.Events,
&i.Headers,
&i.Enabled,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listOutboundWebhooksByUser = `-- name: ListOutboundWebhooksByUser :many
SELECT outbound_webhooks.id, outbound_webhooks.user_id, outbound_webhooks.name, outbound_webhooks.url, outbound_webhooks.secret, outbound_webhooks.events, outbound_webhooks.headers, outbound_webhooks.enabled, outbound_webhooks.created_at, outbound_webhooks.updated_at
FROM outbound_webhooks
WHERE user_id = $1
ORDER BY created_at DESC
`
func (q *Queries) ListOutboundWebhooksByUser(ctx context.Context, userID uuid.UUID) ([]OutboundWebhook, error) {
rows, err := q.db.QueryContext(ctx, listOutboundWebhooksByUser, userID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []OutboundWebhook{}
for rows.Next() {
var i OutboundWebhook
if err := rows.Scan(
&i.ID,
&i.UserID,
&i.Name,
&i.Url,
&i.Secret,
&i.Events,
&i.Headers,
&i.Enabled,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listWebhookDeliveriesByWebhook = `-- name: ListWebhookDeliveriesByWebhook :many
SELECT webhook_deliveries.id, webhook_deliveries.webhook_id, webhook_deliveries.event, webhook_deliveries.payload, webhook_deliveries.status, webhook_deliveries.response_status, webhook_deliveries.response_body, webhook_deliveries.attempts, webhook_deliveries.duration_ms, webhook_deliveries.created_at, webhook_deliveries.delivered_at
FROM webhook_deliveries
WHERE webhook_id = $1
ORDER BY created_at DESC
LIMIT 100
`
func (q *Queries) ListWebhookDeliveriesByWebhook(ctx context.Context, webhookID uuid.UUID) ([]WebhookDelivery, error) {
rows, err := q.db.QueryContext(ctx, listWebhookDeliveriesByWebhook, webhookID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []WebhookDelivery{}
for rows.Next() {
var i WebhookDelivery
if err := rows.Scan(
&i.ID,
&i.WebhookID,
&i.Event,
&i.Payload,
&i.Status,
&i.ResponseStatus,
&i.ResponseBody,
&i.Attempts,
&i.DurationMs,
&i.CreatedAt,
&i.DeliveredAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateOutboundWebhook = `-- name: UpdateOutboundWebhook :exec
UPDATE outbound_webhooks
SET name = $1, url = $2, secret = $3, events = $4, headers = $5, enabled = $6, updated_at = $7
WHERE id = $8 AND user_id = $9
`
type UpdateOutboundWebhookParams struct {
Name string `json:"name"`
Url string `json:"url"`
Secret string `json:"secret"`
Events json.RawMessage `json:"events"`
Headers pqtype.NullRawMessage `json:"headers"`
Enabled bool `json:"enabled"`
UpdatedAt sql.NullTime `json:"updated_at"`
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
}
func (q *Queries) UpdateOutboundWebhook(ctx context.Context, arg UpdateOutboundWebhookParams) error {
_, err := q.db.ExecContext(ctx, updateOutboundWebhook,
arg.Name,
arg.Url,
arg.Secret,
arg.Events,
arg.Headers,
arg.Enabled,
arg.UpdatedAt,
arg.ID,
arg.UserID,
)
return err
}
const updateWebhookDeliveryResult = `-- name: UpdateWebhookDeliveryResult :exec
UPDATE webhook_deliveries
SET status = $1, response_status = $2, response_body = $3, attempts = $4, duration_ms = $5, delivered_at = $6
WHERE id = $7
`
type UpdateWebhookDeliveryResultParams struct {
Status string `json:"status"`
ResponseStatus sql.NullInt32 `json:"response_status"`
ResponseBody sql.NullString `json:"response_body"`
Attempts int32 `json:"attempts"`
DurationMs sql.NullInt32 `json:"duration_ms"`
DeliveredAt sql.NullTime `json:"delivered_at"`
ID uuid.UUID `json:"id"`
}
func (q *Queries) UpdateWebhookDeliveryResult(ctx context.Context, arg UpdateWebhookDeliveryResultParams) error {
_, err := q.db.ExecContext(ctx, updateWebhookDeliveryResult,
arg.Status,
arg.ResponseStatus,
arg.ResponseBody,
arg.Attempts,
arg.DurationMs,
arg.DeliveredAt,
arg.ID,
)
return err
}