fix(security): 體健修復 — 7項 Critical/Major 安全問題全修
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 35s
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 35s
## 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>
This commit is contained in:
@@ -46,7 +46,7 @@ const _getApiBaseUrl = () => {
|
||||
return url
|
||||
}
|
||||
|
||||
const HOST_IPS = ['192.168.0.110', '192.168.0.112', '192.168.0.120', '192.168.0.188']
|
||||
const HOST_IPS = (process.env.NEXT_PUBLIC_HOST_IPS ?? '192.168.0.110,192.168.0.112,192.168.0.120,192.168.0.188').split(',')
|
||||
|
||||
// =============================================================================
|
||||
// Component
|
||||
|
||||
@@ -150,7 +150,7 @@ export function HostGrid({ hosts }: HostGridProps) {
|
||||
☸ K3S CLUSTER (HA)
|
||||
</span>
|
||||
<span style={{ fontSize: 10, color: '#3b7de8' }}>
|
||||
VIP 192.168.0.125 · kubectl :6443 · Web :32335 · API :32334
|
||||
{process.env.NEXT_PUBLIC_K8S_VIP_INFO ?? 'VIP 192.168.0.125 · kubectl :6443 · Web :32335 · API :32334'}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6, padding: 6 }}>
|
||||
|
||||
@@ -137,9 +137,14 @@ function IncidentEvalRow({
|
||||
setExecuting(true)
|
||||
try {
|
||||
const base = getApiBaseUrl()
|
||||
// Phase 20: CSRF Protection — 先取得 token 再執行
|
||||
const csrfRes = await fetch(`${base}/api/v1/csrf/token`, { method: 'GET', credentials: 'include' })
|
||||
if (!csrfRes.ok) throw new Error(`CSRF fetch failed: ${csrfRes.status}`)
|
||||
const csrfData = await csrfRes.json()
|
||||
const csrfHeaders: Record<string, string> = csrfData.token ? { 'X-CSRF-Token': String(csrfData.token) } : {}
|
||||
const res = await fetch(`${base}/api/v1/auto-repair/execute`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: { 'Content-Type': 'application/json', ...csrfHeaders },
|
||||
body: JSON.stringify({ incident_id: incidentId, playbook_id: eval_.playbook_id }),
|
||||
})
|
||||
if (res.ok) setResult(await res.json())
|
||||
|
||||
Reference in New Issue
Block a user