181_prompt_audit.sql 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. -- Independent OpenAI-compatible prompt input audit.
  2. -- Raw prompts and Guard credentials are intentionally absent from PostgreSQL.
  3. CREATE TABLE IF NOT EXISTS prompt_audit_jobs (
  4. id BIGSERIAL PRIMARY KEY,
  5. request_id VARCHAR(128) NOT NULL DEFAULT '',
  6. user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
  7. username_snapshot VARCHAR(255) NOT NULL DEFAULT '',
  8. user_email_snapshot VARCHAR(320) NOT NULL DEFAULT '',
  9. api_key_id BIGINT REFERENCES api_keys(id) ON DELETE SET NULL,
  10. api_key_name_snapshot VARCHAR(255) NOT NULL DEFAULT '',
  11. group_id BIGINT REFERENCES groups(id) ON DELETE SET NULL,
  12. group_name VARCHAR(255) NOT NULL DEFAULT '',
  13. provider VARCHAR(64) NOT NULL DEFAULT '',
  14. endpoint VARCHAR(128) NOT NULL DEFAULT '',
  15. protocol VARCHAR(64) NOT NULL DEFAULT '',
  16. model VARCHAR(255) NOT NULL DEFAULT '',
  17. prompt_hash VARCHAR(64) NOT NULL DEFAULT '',
  18. redacted_preview TEXT NOT NULL DEFAULT '',
  19. prompt_length INT NOT NULL DEFAULT 0,
  20. message_count INT NOT NULL DEFAULT 0,
  21. stage VARCHAR(32) NOT NULL DEFAULT 'http',
  22. execution_mode VARCHAR(32) NOT NULL DEFAULT 'async_audit',
  23. config_version BIGINT NOT NULL DEFAULT 1,
  24. status VARCHAR(32) NOT NULL DEFAULT 'staging',
  25. attempts INT NOT NULL DEFAULT 0,
  26. max_attempts INT NOT NULL DEFAULT 3,
  27. claim_version BIGINT NOT NULL DEFAULT 0,
  28. next_attempt_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  29. processing_started_at TIMESTAMPTZ,
  30. processed_at TIMESTAMPTZ,
  31. last_error_code VARCHAR(64) NOT NULL DEFAULT '',
  32. last_error_message VARCHAR(512) NOT NULL DEFAULT '',
  33. created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  34. updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  35. CONSTRAINT chk_prompt_audit_jobs_status
  36. CHECK (status IN ('staging', 'queued', 'processing', 'retry', 'done', 'failed')),
  37. CONSTRAINT chk_prompt_audit_jobs_execution_mode
  38. CHECK (execution_mode IN ('async_audit', 'blocking')),
  39. CONSTRAINT chk_prompt_audit_jobs_nonnegative
  40. CHECK (
  41. attempts >= 0 AND max_attempts >= 0 AND claim_version >= 0 AND
  42. prompt_length >= 0 AND message_count >= 0 AND config_version >= 1
  43. )
  44. );
  45. CREATE TABLE IF NOT EXISTS prompt_audit_events (
  46. id BIGSERIAL PRIMARY KEY,
  47. job_id BIGINT NOT NULL REFERENCES prompt_audit_jobs(id) ON DELETE CASCADE,
  48. request_id VARCHAR(128) NOT NULL DEFAULT '',
  49. user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
  50. username_snapshot VARCHAR(255) NOT NULL DEFAULT '',
  51. user_email_snapshot VARCHAR(320) NOT NULL DEFAULT '',
  52. api_key_id BIGINT REFERENCES api_keys(id) ON DELETE SET NULL,
  53. api_key_name_snapshot VARCHAR(255) NOT NULL DEFAULT '',
  54. group_id BIGINT REFERENCES groups(id) ON DELETE SET NULL,
  55. group_name VARCHAR(255) NOT NULL DEFAULT '',
  56. provider VARCHAR(64) NOT NULL DEFAULT '',
  57. endpoint VARCHAR(128) NOT NULL DEFAULT '',
  58. protocol VARCHAR(64) NOT NULL DEFAULT '',
  59. model VARCHAR(255) NOT NULL DEFAULT '',
  60. prompt_hash VARCHAR(64) NOT NULL DEFAULT '',
  61. redacted_preview TEXT NOT NULL DEFAULT '',
  62. stage VARCHAR(32) NOT NULL DEFAULT 'http',
  63. decision VARCHAR(32) NOT NULL DEFAULT 'pass',
  64. risk_level VARCHAR(32) NOT NULL DEFAULT 'low',
  65. action VARCHAR(32) NOT NULL DEFAULT 'Allow',
  66. categories JSONB NOT NULL DEFAULT '[]'::jsonb,
  67. matched_scanners JSONB NOT NULL DEFAULT '[]'::jsonb,
  68. scanner_scores JSONB NOT NULL DEFAULT '{}'::jsonb,
  69. scanner_evidence JSONB NOT NULL DEFAULT '{}'::jsonb,
  70. scanner_backend VARCHAR(64) NOT NULL DEFAULT 'qwen3guard-openai',
  71. scanner_version VARCHAR(128) NOT NULL DEFAULT '',
  72. guard_endpoint_id VARCHAR(128) NOT NULL DEFAULT '',
  73. policy_id VARCHAR(128) NOT NULL DEFAULT '',
  74. policy_version INT NOT NULL DEFAULT 0,
  75. config_version BIGINT NOT NULL DEFAULT 1,
  76. chunk_total INT NOT NULL DEFAULT 0,
  77. latency_ms INT NOT NULL DEFAULT 0,
  78. created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  79. CONSTRAINT chk_prompt_audit_events_decision
  80. CHECK (decision IN ('pass', 'flag', 'critical')),
  81. CONSTRAINT chk_prompt_audit_events_risk_level
  82. CHECK (risk_level IN ('low', 'medium', 'high', 'critical')),
  83. CONSTRAINT chk_prompt_audit_events_action
  84. CHECK (action IN ('Allow', 'Warn', 'Block')),
  85. CONSTRAINT chk_prompt_audit_events_nonnegative
  86. CHECK (policy_version >= 0 AND config_version >= 1 AND chunk_total >= 0 AND latency_ms >= 0),
  87. CONSTRAINT chk_prompt_audit_events_categories_json
  88. CHECK (jsonb_typeof(categories) = 'array'),
  89. CONSTRAINT chk_prompt_audit_events_scanners_json
  90. CHECK (jsonb_typeof(matched_scanners) = 'array'),
  91. CONSTRAINT chk_prompt_audit_events_scores_json
  92. CHECK (jsonb_typeof(scanner_scores) = 'object'),
  93. CONSTRAINT chk_prompt_audit_events_evidence_json
  94. CHECK (jsonb_typeof(scanner_evidence) = 'object')
  95. );
  96. CREATE INDEX IF NOT EXISTS idx_prompt_audit_jobs_schedule
  97. ON prompt_audit_jobs(status, next_attempt_at, id);
  98. CREATE INDEX IF NOT EXISTS idx_prompt_audit_jobs_request
  99. ON prompt_audit_jobs(request_id);
  100. CREATE INDEX IF NOT EXISTS idx_prompt_audit_jobs_user_created
  101. ON prompt_audit_jobs(user_id, created_at DESC);
  102. CREATE INDEX IF NOT EXISTS idx_prompt_audit_jobs_api_key_created
  103. ON prompt_audit_jobs(api_key_id, created_at DESC);
  104. CREATE INDEX IF NOT EXISTS idx_prompt_audit_jobs_group_created
  105. ON prompt_audit_jobs(group_id, created_at DESC);
  106. CREATE INDEX IF NOT EXISTS idx_prompt_audit_jobs_prompt_hash
  107. ON prompt_audit_jobs(prompt_hash);
  108. CREATE INDEX IF NOT EXISTS idx_prompt_audit_jobs_created
  109. ON prompt_audit_jobs(created_at DESC, id DESC);
  110. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_job
  111. ON prompt_audit_events(job_id);
  112. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_request
  113. ON prompt_audit_events(request_id);
  114. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_decision_created
  115. ON prompt_audit_events(decision, created_at DESC, id DESC);
  116. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_risk_created
  117. ON prompt_audit_events(risk_level, created_at DESC, id DESC);
  118. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_user_created
  119. ON prompt_audit_events(user_id, created_at DESC, id DESC);
  120. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_api_key_created
  121. ON prompt_audit_events(api_key_id, created_at DESC, id DESC);
  122. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_group_created
  123. ON prompt_audit_events(group_id, created_at DESC, id DESC);
  124. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_prompt_hash
  125. ON prompt_audit_events(prompt_hash);
  126. CREATE INDEX IF NOT EXISTS idx_prompt_audit_events_created
  127. ON prompt_audit_events(created_at DESC, id DESC);