From d494562b136b4a375b12f1d50c0db412a4e196ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dhji=28=EC=A7=80=EB=8C=80=ED=95=9C=29?= Date: Thu, 11 Jun 2026 15:06:17 +0900 Subject: [PATCH] feat: test --- CLAUDE.md | 14 ++++++++++++-- internal/server/webhooks.go | 12 ++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4d40160..30f7936 100644 --- a/CLAUDE.md +++ b/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 ``` ## 핵심 동작 diff --git a/internal/server/webhooks.go b/internal/server/webhooks.go index 96b0524..3328ce6 100644 --- a/internal/server/webhooks.go +++ b/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 {