Browse Source

feat: test

main
지대한 2 weeks ago
parent
commit
d494562b13
  1. 14
      CLAUDE.md
  2. 12
      internal/server/webhooks.go

14
CLAUDE.md

@ -1,3 +1,7 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# slack-notifier
Gitea/Notion webhook 알림을 담당자에게 Slack 개인 DM으로 중계하는 **Go(Gin)** 서버.
@ -7,8 +11,13 @@ Gitea/Notion webhook 알림을 담당자에게 Slack 개인 DM으로 중계하
- **Go 1.26 (Gin)** — 버전은 mise로 관리(`mise use go@1.26`)
- 관리 UI: 표준 `html/template` + HTMX (Node 빌드 불필요), 템플릿은 `go:embed`로 바이너리에 포함
- 실행: `go run .` (기본 `:8000`) · 테스트: `go test ./...` · 빌드: `go build -o slack-notifier .`
- 배포: `docker compose up --build` (distroless 경량 이미지, 실행 위치 미정 — 외부 접근 HTTPS 필요)
- 명령은 `Makefile`에 정리되어 있음(환경은 명령어로 분기, `APP_ENV`에 의존 안 함):
- `make run-dev` / `make run-prod``go run . -env {dev,prod}` (dev=text·debug·콘솔, prod=JSON·info·`logs/app.log`)
- `make test` (`go test ./...`) · `make vet` · `make fmt`(`gofmt -w .`)
- `make build`(현재 OS) · `make build-linux ARCH=arm64|amd64`(EC2 배포용 정적 바이너리, 기본 arm64/Graviton)
- 단일 테스트: `go test ./internal/gitea -run TestName -v` (테스트는 현재 `internal/gitea`에만 있음)
- 헬스체크 `GET /health`, 관리 페이지 `http://localhost:8000/admin/mappings`
- 배포: `docker compose up --build`(distroless, host:6000→컨테이너:8000) 또는 `deploy/`의 systemd+Caddy. 외부 접근은 HTTPS 필요.
## 구조
@ -28,6 +37,7 @@ internal/
admin.go # /admin/mappings (GET/POST/DELETE, HTMX)
templates/ # mappings.html (embed)
data/mappings.json # 런타임 매핑 데이터 (gitignore)
deploy/ # 비-Docker 배포: slack-notifier.service(systemd) + Caddyfile(HTTPS 리버스 프록시) + run.sh
```
## 핵심 동작

12
internal/server/webhooks.go

@ -19,6 +19,13 @@ func (s *Server) handleGitea(c *gin.Context) {
return
}
// 들어온 원본 페이로드 전체를 기록 (검증 전 — 모든 수신 요청 확인용).
slog.Info("gitea webhook received",
"event", c.GetHeader("X-Gitea-Event"),
"delivery", c.GetHeader("X-Gitea-Delivery"),
"signature", c.GetHeader("X-Gitea-Signature"),
"body", string(raw))
if !security.VerifyHMACSHA256(s.cfg.GiteaWebhookSecret, raw, c.GetHeader("X-Gitea-Signature")) {
slog.Warn("gitea signature verification failed")
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid signature"})
@ -43,6 +50,11 @@ func (s *Server) handleNotion(c *gin.Context) {
return
}
// 들어온 원본 페이로드 전체를 기록 (검증 전 — 모든 수신 요청 확인용).
slog.Info("notion webhook received",
"signature", c.GetHeader("X-Notion-Signature"),
"body", string(raw))
// 1) Subscription verification handshake: Notion POSTs a verification_token once.
// Capture it from logs and paste into NOTION_VERIFICATION_TOKEN.
var probe struct {

Loading…
Cancel
Save