Files
awoooi/apps/api/tests/integration/setup_test_schema.sql
Your Name d0591c54b0
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 35s
fix(security): 體健修復 — 7項 Critical/Major 安全問題全修
## Critical 修復 (C1-C5)
- C1: git rm --cached 03-secrets.yaml(CHANGE_ME 模板不再追蹤)
- C2: git rm --cached awoooi.db + .gitignore 加 *.db(SQLite HARD_RULES 違規)
- C3: sentry-tunnel SENTRY_HOST 改為 process.env fallback
- C4: config.py DATABASE_URL 移除 changeme default,改為必填
- C5: run_migration.py 改為 os.environ["DATABASE_URL"]

## Major 修復 (M1-M4)
- M1: auto_repair /execute 加 CSRF 保護 + AutoRepairPanel.tsx 同步
- M2: drift /rollback /adopt 加 CSRF 保護(/internal/scan 保持無 CSRF)
- M3: terminal /intent 加 CSRF 保護 + terminal.store.ts 同步
- M4: live-dashboard HOST_IPS + host-grid VIP 改為 env var

## 其他
- 新增 apps/web/.env.example(6 個 env var 說明)
- K8s deployment-web 補入 3 個新 env var
- 整合測試:新增 aider_event_repository + ai_router_feedback 真實 DB 測試
- test_terminal.py CSRF dependency override 修復

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 01:27:39 +08:00

122 lines
4.5 KiB
SQL

-- Integration Test Schema Setup
-- ================================
-- 為 CI 環境的臨時 PostgreSQL 建立測試所需的 schema
-- 使用: psql $TEST_DATABASE_URL -f setup_test_schema.sql
-- 2026-04-10 Claude Sonnet 4.6 Asia/Taipei
CREATE EXTENSION IF NOT EXISTS vector;
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'incidentstatus') THEN
CREATE TYPE incidentstatus AS ENUM ('INVESTIGATING','MITIGATING','RESOLVED','CLOSED','ESCALATED');
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'severity') THEN
CREATE TYPE severity AS ENUM ('P0','P1','P2','P3');
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'approvalstatus') THEN
CREATE TYPE approvalstatus AS ENUM ('PENDING','APPROVED','REJECTED','EXPIRED','EXECUTION_SUCCESS','EXECUTION_FAILED');
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'risklevel') THEN
CREATE TYPE risklevel AS ENUM ('LOW','MEDIUM','HIGH','CRITICAL');
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrysource') THEN
CREATE TYPE entrysource AS ENUM ('AI_EXTRACTED','HUMAN');
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrystatus') THEN
CREATE TYPE entrystatus AS ENUM ('DRAFT','REVIEW','APPROVED','ARCHIVED','published');
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entrytype') THEN
CREATE TYPE entrytype AS ENUM ('INCIDENT_CASE','RUNBOOK','BEST_PRACTICE','POSTMORTEM','auto_runbook','anti_pattern');
END IF;
END $$;
CREATE TABLE IF NOT EXISTS incidents (
incident_id VARCHAR(30) PRIMARY KEY,
status incidentstatus NOT NULL DEFAULT 'INVESTIGATING',
severity severity NOT NULL DEFAULT 'P2',
signals JSON DEFAULT '[]',
affected_services JSON DEFAULT '[]',
decision_chain JSON DEFAULT '[]',
proposal_ids JSON DEFAULT '[]',
outcome JSON DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
resolved_at TIMESTAMPTZ,
closed_at TIMESTAMPTZ,
ttl_days INTEGER DEFAULT 30,
vectorized BOOLEAN DEFAULT false
);
CREATE TABLE IF NOT EXISTS approval_records (
id VARCHAR(36) PRIMARY KEY,
action VARCHAR(500) NOT NULL,
description TEXT NOT NULL,
status approvalstatus NOT NULL DEFAULT 'PENDING',
risk_level risklevel NOT NULL,
required_signatures INTEGER DEFAULT 1,
current_signatures INTEGER DEFAULT 0,
signatures JSON DEFAULT '[]',
blast_radius JSON DEFAULT '{}',
dry_run_checks JSON DEFAULT '[]',
requested_by VARCHAR,
rejection_reason TEXT,
extra_metadata JSON DEFAULT '{}',
fingerprint VARCHAR,
hit_count INTEGER DEFAULT 1,
last_seen_at TIMESTAMPTZ,
approval_level VARCHAR DEFAULT 'standard',
approval_votes JSONB,
required_votes INTEGER DEFAULT 1,
incident_id VARCHAR,
telegram_message_id INTEGER,
telegram_chat_id INTEGER,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ,
resolved_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS knowledge_entries (
id VARCHAR(36) PRIMARY KEY,
title VARCHAR NOT NULL,
content TEXT,
entry_type entrytype NOT NULL,
category VARCHAR,
tags JSON DEFAULT '[]',
source entrysource NOT NULL DEFAULT 'HUMAN',
status entrystatus NOT NULL DEFAULT 'DRAFT',
related_incident_id VARCHAR,
related_playbook_id VARCHAR,
symptoms_hash VARCHAR,
view_count INTEGER DEFAULT 0,
created_by VARCHAR,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS rag_chunks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
source TEXT NOT NULL,
source_id TEXT NOT NULL,
title TEXT,
chunk_text TEXT NOT NULL,
embedding vector(768),
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- adr091: aider_events schema (2026-04-22 @ Asia/Taipei, 補入 integration test schema)
CREATE TABLE IF NOT EXISTS aider_events (
id BIGSERIAL PRIMARY KEY,
session_id TEXT NOT NULL,
ts TIMESTAMPTZ NOT NULL,
type TEXT NOT NULL,
host TEXT DEFAULT 'ogt-mac',
payload JSONB NOT NULL,
incident_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS aider_events_session_idx ON aider_events(session_id);
CREATE INDEX IF NOT EXISTS aider_events_type_ts_idx ON aider_events(type, ts DESC);
CREATE INDEX IF NOT EXISTS aider_events_ts_idx ON aider_events(ts DESC);