fix(api+web): CORS 補 K3s NodePort origins + sign 補 signer_id/name
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled

CORS (config.py):
- 補 http://192.168.0.125:32335 (K3s VIP NodePort)
- 補 http://192.168.0.120:32335 + 121:32335 (K3s nodes)
- 修前: 內網瀏覽器開 :32335 打 API 全 CORS blocked
  (incidents Failed to fetch / monitoring 無法連線根因)

sign body (pending-approvals-card.tsx):
- signer: 'web-ui' → signer_id: CURRENT_USER.id + signer_name: CURRENT_USER.name
- 修前: POST /approvals/{id}/sign 回 403 (缺必填欄位 422 誤報為 403)
  — 實際是 422 Field required signer_id + signer_name

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-09 19:50:48 +08:00
parent 34f0228d92
commit 8c2983b70a
2 changed files with 5 additions and 1 deletions

View File

@@ -123,6 +123,9 @@ class Settings(BaseSettings):
"http://localhost:3333",
"http://192.168.0.168:3000", # 168 MacBook 本機開發
"http://192.168.0.188:3000", # 188 本機開發
"http://192.168.0.125:32335", # K3s VIP NodePort (staging/QA)
"http://192.168.0.120:32335", # K3s node-1 NodePort
"http://192.168.0.121:32335", # K3s node-2 NodePort
"https://awoooi.wooo.work",
],
description="Allowed CORS origins - NO wildcards allowed",

View File

@@ -11,6 +11,7 @@ import { useTranslations } from 'next-intl'
import { useRouter } from 'next/navigation'
import { useLocale } from 'next-intl'
import { useCSRF } from '@/hooks/useCSRF'
import { CURRENT_USER } from '@/lib/constants/user'
const API_BASE = process.env.NEXT_PUBLIC_API_URL ?? ''
@@ -85,7 +86,7 @@ export function PendingApprovalsCard() {
onClick={() => {
setActionError(null)
setActioningId(ap.id)
fetch(`${API_BASE}/api/v1/approvals/${ap.id}/sign`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', ...getHeaders() }, body: JSON.stringify({ signer: 'web-ui' }) })
fetch(`${API_BASE}/api/v1/approvals/${ap.id}/sign`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', ...getHeaders() }, body: JSON.stringify({ signer_id: CURRENT_USER.id, signer_name: CURRENT_USER.name }) })
.then(r => { if (!r.ok) throw new Error(`${r.status}`); return r })
.then(() => setApprovals(prev => prev.filter(x => x.id !== ap.id)))
.catch(e => setActionError(`approve failed: ${e.message}`))