ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s
123 lines
4.9 KiB
Go
123 lines
4.9 KiB
Go
package notify
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// hanFreeItems 는 CJK 한자가 없는 항목(ASCII 제목·유형·요약)만 만든다.
|
|
// 라벨이 중국어로 되돌아가면 렌더 결과 전체에 한자가 생기므로, 데이터가
|
|
// 한자 0 일 때만 "출력 전체에 한자 0" 단언이 라벨 회귀를 정확히 잡아낸다.
|
|
func hanFreeItems(n int) []Item {
|
|
items := make([]Item, 0, n)
|
|
for i := 0; i < n; i++ {
|
|
items = append(items, Item{
|
|
FindingID: int64(i + 1),
|
|
Name: "login-flaw",
|
|
VulnClass: "SQLi",
|
|
Severity: "high",
|
|
Summary: "SQL injection via q param",
|
|
Assets: []string{"a.example.com"},
|
|
})
|
|
}
|
|
return items
|
|
}
|
|
|
|
// TestMarkdownTitleLocalized 는 markdown 계열 채널(dingtalk·wecom)과 제목을
|
|
// 공유하는 feishu·html·telegram·webhook 이 함께 쓰는 markdownTitle 이 한국어인지
|
|
// 검사한다. 하나라도 중국어로 되돌아가면 이 다섯 채널의 제목이 전부 혼재된다.
|
|
func TestMarkdownTitleLocalized(t *testing.T) {
|
|
// 다건(汇总): "취약점 요약 · 총 N건"
|
|
got := markdownTitle(Message{Batch: true, Items: hanFreeItems(3)})
|
|
assertKorean(t, "markdownTitle(batch)", got)
|
|
if !strings.Contains(got, "취약점 요약") || !strings.Contains(got, "총 3건") {
|
|
t.Errorf("다건 제목이 '취약점 요약 · 총 3건' 형태여야 합니다, 받은 값 %q", got)
|
|
}
|
|
// 항목 없음: "취약점 알림"
|
|
empty := markdownTitle(Message{})
|
|
assertKorean(t, "markdownTitle(empty)", empty)
|
|
if empty != "취약점 알림" {
|
|
t.Errorf("빈 메시지 제목은 '취약점 알림' 이어야 합니다, 받은 값 %q", empty)
|
|
}
|
|
}
|
|
|
|
// TestMarkdownBatchIntroLocalized 는 다이제스트 머리말(시간창·건수·초과 안내)이
|
|
// 한국어인지 검사한다. 항목 데이터가 한자 0 이므로 출력에 한자가 보이면 머리말
|
|
// 문구가 중국어로 회귀한 것이다.
|
|
func TestMarkdownBatchIntroLocalized(t *testing.T) {
|
|
items := hanFreeItems(3)
|
|
|
|
// 시간창 있음: "최근 N분간 신규 취약점 N건"
|
|
win := markdownBatchIntro(Message{Batch: true, WindowMinutes: 30}, items, 3)
|
|
if hasHan(win) {
|
|
t.Errorf("시간창 머리말에 중국어 한자가 남았습니다: %q", win)
|
|
}
|
|
if !strings.Contains(win, "최근 30분간") || !strings.Contains(win, "신규 취약점 3건") {
|
|
t.Errorf("시간창 머리말이 '최근 30분간 신규 취약점 3건' 형태여야 합니다, 받은 값 %q", win)
|
|
}
|
|
|
|
// 시간창 없음: "신규 취약점 N건"(분간 표기 없음)
|
|
noWin := markdownBatchIntro(Message{Batch: true}, items, 3)
|
|
if hasHan(noWin) {
|
|
t.Errorf("머리말에 중국어 한자가 남았습니다: %q", noWin)
|
|
}
|
|
if !strings.Contains(noWin, "신규 취약점 3건") || strings.Contains(noWin, "분간") {
|
|
t.Errorf("시간창 없는 머리말은 '신규 취약점 3건'(분간 표기 없음)이어야 합니다, 받은 값 %q", noWin)
|
|
}
|
|
|
|
// 일부만 담겼을 때: "(이 메시지에는 앞 N건만 … 나머지 N건은 다음 메시지에서 …)"
|
|
trunc := markdownBatchIntro(Message{Batch: true, WindowMinutes: 30}, items, 5)
|
|
if hasHan(trunc) {
|
|
t.Errorf("초과 안내에 중국어 한자가 남았습니다: %q", trunc)
|
|
}
|
|
for _, want := range []string{"앞 3건만", "나머지 2건", "다음 메시지에서"} {
|
|
if !strings.Contains(trunc, want) {
|
|
t.Errorf("초과 안내에 %q 가 있어야 합니다, 받은 값 %q", want, trunc)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestWriteItemLabelsLocalized 는 단건 상세 렌더(markdown 3채널 공유 경로)의
|
|
// 필드 라벨(상태 변경·유형·자산·개요)과 상세 링크가 한국어인지 검사한다.
|
|
func TestWriteItemLabelsLocalized(t *testing.T) {
|
|
it := Item{
|
|
Name: "login-flaw",
|
|
VulnClass: "SQLi",
|
|
Severity: "high",
|
|
Summary: "SQL injection via q param",
|
|
Assets: []string{"a.example.com"},
|
|
DetailURL: "https://platform.example/finding/1",
|
|
FromStatus: "pending",
|
|
ToStatus: "fixed",
|
|
}
|
|
var b strings.Builder
|
|
writeItem(&b, it, "", true)
|
|
got := b.String()
|
|
|
|
assertKorean(t, "writeItem(single)", got)
|
|
for _, want := range []string{
|
|
"**상태 변경**: 처리 대기 → 수정됨",
|
|
"**유형**: SQLi",
|
|
"**자산**: a.example.com",
|
|
"**개요**: SQL injection via q param",
|
|
"[상세 보기](https://platform.example/finding/1)",
|
|
} {
|
|
if !strings.Contains(got, want) {
|
|
t.Errorf("단건 렌더에 %q 가 있어야 합니다:\n%s", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestMarkdownBodyFooterLocalized 는 다건 본문 끝의 플랫폼 입구 링크가
|
|
// 한국어인지 검사한다(HomeURL 이 있을 때만 붙는다).
|
|
func TestMarkdownBodyFooterLocalized(t *testing.T) {
|
|
m := Message{Batch: true, HomeURL: "https://platform.example", Items: hanFreeItems(2)}
|
|
body, kept := markdownBody(m, 0)
|
|
if kept != 2 {
|
|
t.Fatalf("한도 없음(0)이면 2건 모두 담겨야 합니다, 받은 값 %d", kept)
|
|
}
|
|
if !strings.Contains(body, "[플랫폼에서 전체 보기](https://platform.example)") {
|
|
t.Errorf("본문 끝에 '플랫폼에서 전체 보기' 링크가 있어야 합니다:\n%s", body)
|
|
}
|
|
}
|