migration reorg basically done

This commit is contained in:
2026-02-05 16:56:45 -06:00
parent 343488b3eb
commit c62f41669d
33 changed files with 1569 additions and 355 deletions

View File

@@ -1,5 +1,5 @@
-- Migration: Event System
-- Description: Creates trigger, sensor, event, and rule tables (with webhook_config, is_adhoc from start)
-- Description: Creates trigger, sensor, event, and enforcement tables (with webhook_config, is_adhoc from start)
-- Version: 20250101000003
-- ============================================================================
@@ -71,6 +71,7 @@ CREATE TABLE sensor (
trigger BIGINT NOT NULL REFERENCES trigger(id) ON DELETE CASCADE,
trigger_ref TEXT NOT NULL,
enabled BOOLEAN NOT NULL,
is_adhoc BOOLEAN NOT NULL DEFAULT FALSE,
param_schema JSONB,
config JSONB,
created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
@@ -81,6 +82,31 @@ CREATE TABLE sensor (
CONSTRAINT sensor_ref_format CHECK (ref ~ '^[^.]+\.[^.]+$')
);
-- Indexes
CREATE INDEX idx_sensor_ref ON sensor(ref);
CREATE INDEX idx_sensor_pack ON sensor(pack);
CREATE INDEX idx_sensor_runtime ON sensor(runtime);
CREATE INDEX idx_sensor_trigger ON sensor(trigger);
CREATE INDEX idx_sensor_enabled ON sensor(enabled) WHERE enabled = TRUE;
CREATE INDEX idx_sensor_is_adhoc ON sensor(is_adhoc) WHERE is_adhoc = true;
CREATE INDEX idx_sensor_created ON sensor(created DESC);
-- Trigger
CREATE TRIGGER update_sensor_updated
BEFORE UPDATE ON sensor
FOR EACH ROW
EXECUTE FUNCTION update_updated_column();
-- Comments
COMMENT ON TABLE sensor IS 'Sensors monitor for events and create trigger instances';
COMMENT ON COLUMN sensor.ref IS 'Unique sensor reference (format: pack.name)';
COMMENT ON COLUMN sensor.label IS 'Human-readable sensor name';
COMMENT ON COLUMN sensor.entrypoint IS 'Script or command to execute';
COMMENT ON COLUMN sensor.runtime IS 'Runtime environment for execution';
COMMENT ON COLUMN sensor.trigger IS 'Trigger type this sensor creates events for';
COMMENT ON COLUMN sensor.enabled IS 'Whether this sensor is active';
COMMENT ON COLUMN sensor.is_adhoc IS 'True if sensor was manually created (ad-hoc), false if installed from pack';
-- ============================================================================
-- EVENT TABLE
-- ============================================================================
@@ -173,3 +199,6 @@ COMMENT ON COLUMN enforcement.status IS 'Processing status';
COMMENT ON COLUMN enforcement.payload IS 'Event payload for rule evaluation';
COMMENT ON COLUMN enforcement.condition IS 'Logical operator for conditions (any=OR, all=AND)';
COMMENT ON COLUMN enforcement.conditions IS 'Condition expressions to evaluate';
-- Note: Rule table will be created in migration 20250101000006 after action table exists
-- Note: Foreign key constraints for enforcement.rule and event.rule will be added in that migration

View File

@@ -17,6 +17,7 @@ CREATE TABLE action (
runtime BIGINT REFERENCES runtime(id),
param_schema JSONB,
out_schema JSONB,
is_adhoc BOOLEAN NOT NULL DEFAULT FALSE,
created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated TIMESTAMPTZ NOT NULL DEFAULT NOW(),
@@ -25,6 +26,30 @@ CREATE TABLE action (
CONSTRAINT action_ref_format CHECK (ref ~ '^[^.]+\.[^.]+$')
);
-- Indexes
CREATE INDEX idx_action_ref ON action(ref);
CREATE INDEX idx_action_pack ON action(pack);
CREATE INDEX idx_action_runtime ON action(runtime);
CREATE INDEX idx_action_is_adhoc ON action(is_adhoc) WHERE is_adhoc = true;
CREATE INDEX idx_action_created ON action(created DESC);
-- Trigger
CREATE TRIGGER update_action_updated
BEFORE UPDATE ON action
FOR EACH ROW
EXECUTE FUNCTION update_updated_column();
-- Comments
COMMENT ON TABLE action IS 'Actions are executable tasks that can be triggered';
COMMENT ON COLUMN action.ref IS 'Unique action reference (format: pack.name)';
COMMENT ON COLUMN action.pack IS 'Pack this action belongs to';
COMMENT ON COLUMN action.label IS 'Human-readable action name';
COMMENT ON COLUMN action.entrypoint IS 'Script or command to execute';
COMMENT ON COLUMN action.runtime IS 'Runtime environment for execution';
COMMENT ON COLUMN action.param_schema IS 'JSON schema for action parameters';
COMMENT ON COLUMN action.out_schema IS 'JSON schema for action output';
COMMENT ON COLUMN action.is_adhoc IS 'True if action was manually created (ad-hoc), false if installed from pack';
-- ============================================================================
-- Add foreign key constraint for policy table

View File

@@ -1,5 +1,5 @@
-- Migration: Execution System
-- Description: Creates execution (with workflow columns) and inquiry tables
-- Description: Creates execution (with workflow columns), inquiry, and rule tables
-- Version: 20250101000006
-- ============================================================================
@@ -105,3 +105,76 @@ COMMENT ON COLUMN inquiry.timeout_at IS 'When this inquiry expires';
COMMENT ON COLUMN inquiry.responded_at IS 'When the response was received';
-- ============================================================================
-- ============================================================================
-- RULE TABLE
-- ============================================================================
CREATE TABLE rule (
id BIGSERIAL PRIMARY KEY,
ref TEXT NOT NULL UNIQUE,
pack BIGINT NOT NULL REFERENCES pack(id) ON DELETE CASCADE,
pack_ref TEXT NOT NULL,
label TEXT NOT NULL,
description TEXT NOT NULL,
action BIGINT NOT NULL REFERENCES action(id),
action_ref TEXT NOT NULL,
trigger BIGINT NOT NULL REFERENCES trigger(id),
trigger_ref TEXT NOT NULL,
conditions JSONB NOT NULL DEFAULT '[]'::jsonb,
action_params JSONB DEFAULT '{}'::jsonb,
trigger_params JSONB DEFAULT '{}'::jsonb,
enabled BOOLEAN NOT NULL,
is_adhoc BOOLEAN NOT NULL DEFAULT FALSE,
created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- Constraints
CONSTRAINT rule_ref_lowercase CHECK (ref = LOWER(ref)),
CONSTRAINT rule_ref_format CHECK (ref ~ '^[^.]+\.[^.]+$')
);
-- Indexes
CREATE INDEX idx_rule_ref ON rule(ref);
CREATE INDEX idx_rule_pack ON rule(pack);
CREATE INDEX idx_rule_action ON rule(action);
CREATE INDEX idx_rule_trigger ON rule(trigger);
CREATE INDEX idx_rule_enabled ON rule(enabled) WHERE enabled = TRUE;
CREATE INDEX idx_rule_is_adhoc ON rule(is_adhoc) WHERE is_adhoc = true;
CREATE INDEX idx_rule_created ON rule(created DESC);
CREATE INDEX idx_rule_trigger_enabled ON rule(trigger, enabled);
CREATE INDEX idx_rule_action_enabled ON rule(action, enabled);
CREATE INDEX idx_rule_pack_enabled ON rule(pack, enabled);
CREATE INDEX idx_rule_action_params_gin ON rule USING GIN (action_params);
CREATE INDEX idx_rule_trigger_params_gin ON rule USING GIN (trigger_params);
-- Trigger
CREATE TRIGGER update_rule_updated
BEFORE UPDATE ON rule
FOR EACH ROW
EXECUTE FUNCTION update_updated_column();
-- Comments
COMMENT ON TABLE rule IS 'Rules link triggers to actions with conditions';
COMMENT ON COLUMN rule.ref IS 'Unique rule reference (format: pack.name)';
COMMENT ON COLUMN rule.label IS 'Human-readable rule name';
COMMENT ON COLUMN rule.action IS 'Action to execute when rule triggers';
COMMENT ON COLUMN rule.trigger IS 'Trigger that activates this rule';
COMMENT ON COLUMN rule.conditions IS 'Condition expressions to evaluate before executing action';
COMMENT ON COLUMN rule.action_params IS 'Parameter overrides for the action';
COMMENT ON COLUMN rule.trigger_params IS 'Parameter overrides for the trigger';
COMMENT ON COLUMN rule.enabled IS 'Whether this rule is active';
COMMENT ON COLUMN rule.is_adhoc IS 'True if rule was manually created (ad-hoc), false if installed from pack';
-- ============================================================================
-- Add foreign key constraints now that rule table exists
ALTER TABLE enforcement
ADD CONSTRAINT enforcement_rule_fkey
FOREIGN KEY (rule) REFERENCES rule(id) ON DELETE SET NULL;
ALTER TABLE event
ADD CONSTRAINT event_rule_fkey
FOREIGN KEY (rule) REFERENCES rule(id) ON DELETE SET NULL;
-- ============================================================================

View File

@@ -6,36 +6,100 @@
-- EXECUTION CHANGE NOTIFICATION
-- ============================================================================
-- Function to notify on execution changes
CREATE OR REPLACE FUNCTION notify_execution_change()
-- Function to notify on execution creation
CREATE OR REPLACE FUNCTION notify_execution_created()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
enforcement_rule_ref TEXT;
enforcement_trigger_ref TEXT;
BEGIN
-- Lookup enforcement details if this execution is linked to an enforcement
IF NEW.enforcement IS NOT NULL THEN
SELECT rule_ref, trigger_ref
INTO enforcement_rule_ref, enforcement_trigger_ref
FROM enforcement
WHERE id = NEW.enforcement;
END IF;
payload := json_build_object(
'entity_type', 'execution',
'entity_id', NEW.id,
'id', NEW.id,
'ref', NEW.ref,
'action_id', NEW.action,
'action_ref', NEW.action_ref,
'status', NEW.status,
'rule', NEW.rule,
'rule_ref', NEW.rule_ref,
'enforcement', NEW.enforcement,
'rule_ref', enforcement_rule_ref,
'trigger_ref', enforcement_trigger_ref,
'parent', NEW.parent,
'result', NEW.result,
'created', NEW.created,
'updated', NEW.updated
);
PERFORM pg_notify('execution_change', payload::text);
PERFORM pg_notify('execution_created', payload::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on execution table
CREATE TRIGGER execution_change_notify
AFTER INSERT OR UPDATE ON execution
FOR EACH ROW
EXECUTE FUNCTION notify_execution_change();
-- Function to notify on execution status changes
CREATE OR REPLACE FUNCTION notify_execution_status_changed()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
enforcement_rule_ref TEXT;
enforcement_trigger_ref TEXT;
BEGIN
-- Only notify on updates, not inserts
IF TG_OP = 'UPDATE' AND OLD.status IS DISTINCT FROM NEW.status THEN
-- Lookup enforcement details if this execution is linked to an enforcement
IF NEW.enforcement IS NOT NULL THEN
SELECT rule_ref, trigger_ref
INTO enforcement_rule_ref, enforcement_trigger_ref
FROM enforcement
WHERE id = NEW.enforcement;
END IF;
COMMENT ON FUNCTION notify_execution_change() IS 'Sends execution change notifications via PostgreSQL LISTEN/NOTIFY';
payload := json_build_object(
'entity_type', 'execution',
'entity_id', NEW.id,
'id', NEW.id,
'action_id', NEW.action,
'action_ref', NEW.action_ref,
'status', NEW.status,
'old_status', OLD.status,
'enforcement', NEW.enforcement,
'rule_ref', enforcement_rule_ref,
'trigger_ref', enforcement_trigger_ref,
'parent', NEW.parent,
'result', NEW.result,
'created', NEW.created,
'updated', NEW.updated
);
PERFORM pg_notify('execution_status_changed', payload::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on execution table for creation
CREATE TRIGGER execution_created_notify
AFTER INSERT ON execution
FOR EACH ROW
EXECUTE FUNCTION notify_execution_created();
-- Trigger on execution table for status changes
CREATE TRIGGER execution_status_changed_notify
AFTER UPDATE ON execution
FOR EACH ROW
EXECUTE FUNCTION notify_execution_status_changed();
COMMENT ON FUNCTION notify_execution_created() IS 'Sends execution creation notifications via PostgreSQL LISTEN/NOTIFY';
COMMENT ON FUNCTION notify_execution_status_changed() IS 'Sends execution status change notifications via PostgreSQL LISTEN/NOTIFY';
-- ============================================================================
-- EVENT CREATION NOTIFICATION
@@ -48,11 +112,16 @@ DECLARE
payload JSON;
BEGIN
payload := json_build_object(
'entity_type', 'event',
'entity_id', NEW.id,
'id', NEW.id,
'ref', NEW.ref,
'trigger', NEW.trigger,
'trigger_ref', NEW.trigger_ref,
'source', NEW.source,
'source_ref', NEW.source_ref,
'rule', NEW.rule,
'rule_ref', NEW.rule_ref,
'payload', NEW.payload,
'created', NEW.created
);
@@ -74,31 +143,146 @@ COMMENT ON FUNCTION notify_event_created() IS 'Sends event creation notification
-- ENFORCEMENT CHANGE NOTIFICATION
-- ============================================================================
-- Function to notify on enforcement changes
CREATE OR REPLACE FUNCTION notify_enforcement_change()
-- Function to notify on enforcement creation
CREATE OR REPLACE FUNCTION notify_enforcement_created()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
payload := json_build_object(
'entity_type', 'enforcement',
'entity_id', NEW.id,
'id', NEW.id,
'ref', NEW.ref,
'rule', NEW.rule,
'rule_ref', NEW.rule_ref,
'trigger_ref', NEW.trigger_ref,
'event', NEW.event,
'status', NEW.status,
'condition', NEW.condition,
'conditions', NEW.conditions,
'config', NEW.config,
'payload', NEW.payload,
'created', NEW.created,
'updated', NEW.updated
);
PERFORM pg_notify('enforcement_change', payload::text);
PERFORM pg_notify('enforcement_created', payload::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on enforcement table
CREATE TRIGGER enforcement_change_notify
AFTER INSERT OR UPDATE ON enforcement
CREATE TRIGGER enforcement_created_notify
AFTER INSERT ON enforcement
FOR EACH ROW
EXECUTE FUNCTION notify_enforcement_change();
EXECUTE FUNCTION notify_enforcement_created();
COMMENT ON FUNCTION notify_enforcement_change() IS 'Sends enforcement change notifications via PostgreSQL LISTEN/NOTIFY';
COMMENT ON FUNCTION notify_enforcement_created() IS 'Sends enforcement creation notifications via PostgreSQL LISTEN/NOTIFY';
-- ============================================================================
-- INQUIRY NOTIFICATIONS
-- ============================================================================
-- Function to notify on inquiry creation
CREATE OR REPLACE FUNCTION notify_inquiry_created()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
payload := json_build_object(
'entity_type', 'inquiry',
'entity_id', NEW.id,
'id', NEW.id,
'execution', NEW.execution,
'status', NEW.status,
'ttl', NEW.ttl,
'created', NEW.created
);
PERFORM pg_notify('inquiry_created', payload::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Function to notify on inquiry response
CREATE OR REPLACE FUNCTION notify_inquiry_responded()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
-- Only notify when status changes to 'responded'
IF TG_OP = 'UPDATE' AND NEW.status = 'responded' AND OLD.status != 'responded' THEN
payload := json_build_object(
'entity_type', 'inquiry',
'entity_id', NEW.id,
'id', NEW.id,
'execution', NEW.execution,
'status', NEW.status,
'response', NEW.response,
'updated', NEW.updated
);
PERFORM pg_notify('inquiry_responded', payload::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on inquiry table for creation
CREATE TRIGGER inquiry_created_notify
AFTER INSERT ON inquiry
FOR EACH ROW
EXECUTE FUNCTION notify_inquiry_created();
-- Trigger on inquiry table for responses
CREATE TRIGGER inquiry_responded_notify
AFTER UPDATE ON inquiry
FOR EACH ROW
EXECUTE FUNCTION notify_inquiry_responded();
COMMENT ON FUNCTION notify_inquiry_created() IS 'Sends inquiry creation notifications via PostgreSQL LISTEN/NOTIFY';
COMMENT ON FUNCTION notify_inquiry_responded() IS 'Sends inquiry response notifications via PostgreSQL LISTEN/NOTIFY';
-- ============================================================================
-- WORKFLOW EXECUTION NOTIFICATIONS
-- ============================================================================
-- Function to notify on workflow execution status changes
CREATE OR REPLACE FUNCTION notify_workflow_execution_status_changed()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
-- Only notify for workflow executions when status changes
IF TG_OP = 'UPDATE' AND NEW.is_workflow = true AND OLD.status IS DISTINCT FROM NEW.status THEN
payload := json_build_object(
'entity_type', 'execution',
'entity_id', NEW.id,
'id', NEW.id,
'action_ref', NEW.action_ref,
'status', NEW.status,
'old_status', OLD.status,
'workflow_def', NEW.workflow_def,
'parent', NEW.parent,
'created', NEW.created,
'updated', NEW.updated
);
PERFORM pg_notify('workflow_execution_status_changed', payload::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on execution table for workflow status changes
CREATE TRIGGER workflow_execution_status_changed_notify
AFTER UPDATE ON execution
FOR EACH ROW
WHEN (NEW.is_workflow = true)
EXECUTE FUNCTION notify_workflow_execution_status_changed();
COMMENT ON FUNCTION notify_workflow_execution_status_changed() IS 'Sends workflow execution status change notifications via PostgreSQL LISTEN/NOTIFY';

View File

@@ -0,0 +1,56 @@
-- Migration: Worker Table
-- Description: Creates worker table for tracking worker registration and heartbeat
-- Version: 20250101000014
-- ============================================================================
-- WORKER TABLE
-- ============================================================================
CREATE TABLE worker (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
worker_type worker_type_enum NOT NULL,
worker_role worker_role_enum NOT NULL,
runtime BIGINT REFERENCES runtime(id) ON DELETE SET NULL,
host TEXT,
port INTEGER,
status worker_status_enum NOT NULL DEFAULT 'active',
capabilities JSONB,
meta JSONB,
last_heartbeat TIMESTAMPTZ,
created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_worker_name ON worker(name);
CREATE INDEX idx_worker_type ON worker(worker_type);
CREATE INDEX idx_worker_role ON worker(worker_role);
CREATE INDEX idx_worker_runtime ON worker(runtime);
CREATE INDEX idx_worker_status ON worker(status);
CREATE INDEX idx_worker_last_heartbeat ON worker(last_heartbeat DESC) WHERE last_heartbeat IS NOT NULL;
CREATE INDEX idx_worker_created ON worker(created DESC);
CREATE INDEX idx_worker_status_role ON worker(status, worker_role);
CREATE INDEX idx_worker_capabilities_gin ON worker USING GIN (capabilities);
CREATE INDEX idx_worker_meta_gin ON worker USING GIN (meta);
-- Trigger
CREATE TRIGGER update_worker_updated
BEFORE UPDATE ON worker
FOR EACH ROW
EXECUTE FUNCTION update_updated_column();
-- Comments
COMMENT ON TABLE worker IS 'Worker registration and tracking table for action and sensor workers';
COMMENT ON COLUMN worker.name IS 'Unique worker identifier (typically hostname-based)';
COMMENT ON COLUMN worker.worker_type IS 'Worker deployment type (local or remote)';
COMMENT ON COLUMN worker.worker_role IS 'Worker role (action or sensor)';
COMMENT ON COLUMN worker.runtime IS 'Runtime environment this worker supports (optional)';
COMMENT ON COLUMN worker.host IS 'Worker host address';
COMMENT ON COLUMN worker.port IS 'Worker port number';
COMMENT ON COLUMN worker.status IS 'Worker operational status';
COMMENT ON COLUMN worker.capabilities IS 'Worker capabilities (e.g., max_concurrent_executions, supported runtimes)';
COMMENT ON COLUMN worker.meta IS 'Additional worker metadata';
COMMENT ON COLUMN worker.last_heartbeat IS 'Timestamp of last heartbeat from worker';
-- ============================================================================