# Gateway Slack Events 서명 불일치 및 500 매핑 이슈 정리

**작성일**: 2026-02-27  
**작성자**: Codex  
**상태**: 진행 중 (핵심 버그 2건 반영 완료, 최종 모니터링 필요)

## 문제 요약

- `/gateway/slack/events` 요청이 반복적으로 `500` 반환
- 초기 에러는 `rb8001`에서 `could not convert string to float: ''`
- 이후 `float('')` 가드 추가 후에도 `Invalid Slack signature` + `500` 지속

## 확인된 사실 (로그/코드 기준)

1. **재현 시각/패턴**
- 최초 관측: `2026-02-13 14:39 (KST)`  
- 반복 관측: `2026-02-19`, `2026-02-21`, `2026-02-27`  
- 2026-02-27 기준 nginx `access.json`에서 `/gateway/slack/events`가 전부 `500`으로 관측

2. **게이트웨이(51123) 로그**
- 실유입 시 `X-Slack-Signature`, `X-Slack-Request-Timestamp` 헤더 키는 전달됨
- 동시각 `rb8001` 호출 결과가 `500`으로 반환됨

3. **rb8001(51124) 로그**
- `Invalid Slack signature` 직후 `Error processing Slack event: 403: Invalid signature`
- 최종 응답이 `500 Internal Server Error`로 기록됨

## 잘못된 과정 (이번 장애에서의 오판/미흡)

1. **헤더 키 전달 누락만 원인으로 먼저 고정한 점**
- 실제로는 헤더 키 전달 문제 + 본문 원문 보존 문제 + 403→500 매핑 문제가 함께 존재

2. **이벤트 본문 원문 보존 미처리**
- `robeing-gateway` `/slack/events` 경로에서 `request.json()` 후 `json=` 재전달 구조였음
- Slack 서명 검증은 원문 바디 기준이므로 재직렬화 시 검증 불일치 가능

3. **rb8001 예외 처리 구조 미정리**
- `HTTPException(403)`를 광범위 `except Exception`에서 잡아 다시 `500`으로 변환
- 인증 실패를 서버 장애처럼 보이게 만듦

## 원인 정리 (우선순위)

1. **1순위**: `rb8001`의 `403 -> 500` 재매핑 구조 (`slack_endpoint.py`)  
2. **2순위**: `gateway /slack/events` 본문 재직렬화(`json=`)로 인한 서명 불일치 가능성  
3. **보조 요인 아님**: DB/환경변수 변경은 이번 트리거 직접 증거가 약함

## 이번에 반영된 수정 (51123)

### A. 헤더 전달 보강
- `X-Slack-Signature`, `X-Slack-Request-Timestamp` 전달
- 커밋: `9097eee` (`fix: forward Slack signature headers on /slack/events`)

### B. 원문 body 보존 전달
- `/slack/events`: `raw_body = await request.body()`
- rb8001 전송: `client.post(..., content=raw_body, headers=...)`
- `Content-Type` 전달 추가
- 커밋: `12c06ca` (`fix(slack): preserve raw event body for signature verification`)

## 이번에 반영된 수정 (51124, Codex)

### C. timestamp 파싱 가드 추가
- 파일: `rb8001/app/router/slack_endpoint.py`
- 변경: `timestamp` 빈값/비정상값(`''`, non-numeric)에서 `float()` 예외가 나지 않도록 방어
- 커밋: `c1321a7` (`fix(slack): guard invalid slack timestamp parsing`)

### D. 403 -> 500 재매핑 제거
- 파일: `rb8001/app/router/slack_endpoint.py`
- 변경: `except HTTPException: raise` 분기 추가로 인증 실패 상태코드(403) 보존
- 커밋: `b19abbd` (`fix(slack): preserve HTTP status for signature failures`)

## 51124 배포/검증 결과 (2026-02-27)

1. **자동배포 반영 확인**
- `git push origin main` 후 `docker ps`에서 `rb8001` 재시작 확인 (`Up 52 seconds (healthy)` 시점 확인)
- `curl http://localhost:8001/health` → `200`

2. **상태코드 동작 확인**
- 무서명 테스트 요청: `POST /api/slack/events` → `403 {"detail":"Invalid signature"}`
- 기존처럼 `500`으로 재매핑되지 않음

3. **실유입 로그 확인**
- `docker logs rb8001` 최근 구간에서 `192.168.219.45 -> POST /api/slack/events`가 `200 OK` 다건 확인
- `could not convert string to float` 및 `/api/slack/events 500` 재발 로그 미확인

## 아직 남은 조치 (최종 운영 확인)

1. **서명 검증 안정화 최종 모니터링**
- `/gateway/slack/events` 실유입 기준으로 200/403 분포를 24시간 관찰
- 재발 시 게이트웨이 원문 body 전달(`content=raw_body`) 경로와 nginx 로그를 시각 동기화해 재검증

## 후속 복구

- 2026-03-17 실제 재발은 게이트 본문 전달 문제가 아니라 24서버 `rb8001`의 `SLACK_SIGNING_SECRET` 오값과 compose 빈값 덮어쓰기 구조가 직접 원인이었습니다.
- 상세 복구 기록: [rb8001 Slack Signing Secret 오값 복구 및 실유입 검증](../worklog/260317_rb8001_slack_signing_secret_오값복구_및_실유입검증.md)

## 관련 파일

- `robeing-gateway/app/routers/slack.py`
- `robeing-gateway/app/services/slack_proxy.py`
- `rb8001/app/router/slack_endpoint.py`
- `/var/log/nginx/access.json`
- `/mnt/hdd/logs/51124-server/rb8001/rb8001.log`
