From 82a4c72080845a77414013f829960faa29ebae8d Mon Sep 17 00:00:00 2001 From: "DESKTOP-TKLFCPR\\ython" Date: Fri, 29 May 2026 22:50:29 +0900 Subject: [PATCH] =?UTF-8?q?feat(itsm):=20PMS/=EC=A4=80=EC=88=98=EC=84=B1/J?= =?UTF-8?q?Meter/=EA=B3=B5=EA=B3=B5=EA=B8=B0=EA=B4=80=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20+=20Nifty=20UI=20+=20=EB=A1=9C=EA=B3=A0=20Copyright?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [PMS 완성] - core/si_report.py: 일/주/월 보고서 (Excel/HTML/PDF/DOCX/PPTX) - routers/si_report.py: daily|weekly|monthly + 메신저 발송 - routers/deliverables.py: 산출물 CRUD + 제출/검토 - si_issues.py: 이슈→SR 자동 연결 - scheduler.py: 일일 18:00 + 주간 금 17:00 자동 보고서 - models.py: Deliverable 모델 [준수성 자동 점검] - core/compliance_check.py: SC-8개/WA-7개/PI-6개 규칙 - routers/compliance.py: 스캔 + HTML/Excel 보고서 [JMeter 성능 테스트] - routers/jmeter.py: JTL 업로드 + 내장 부하 테스트 + 보고서 [공공기관 필수 기능] - routers/public_checklist.py: 행안부 기준 19개 항목 [UI/브랜드] - 로고(ziologo.png) + Copyright 2026 All Rights Reserved - Nifty 계층형 사이드바 (PMS 서브메뉴) - X-Powered-By + X-Copyright 응답 헤더 - manual/15_UI_Nifty_가이드.md Co-Authored-By: Claude Sonnet 4.6 --- itsm/core/compliance_check.py | 291 +++++++++++++ itsm/core/oauth.py | 199 +++++++++ itsm/core/scheduler.py | 76 ++++ itsm/core/si_report.py | 683 +++++++++++++++++++++++++++++++ itsm/guardia_itsm.db.bak | Bin 0 -> 933888 bytes itsm/main.py | 28 +- itsm/models.py | 98 +++++ itsm/requirements.txt | 6 + itsm/routers/auth.py | 92 +++++ itsm/routers/compliance.py | 229 +++++++++++ itsm/routers/deliverables.py | 263 ++++++++++++ itsm/routers/jmeter.py | 431 +++++++++++++++++++ itsm/routers/public_checklist.py | 354 ++++++++++++++++ itsm/routers/si_issues.py | 59 +++ itsm/routers/si_report.py | 189 +++++++++ itsm/static/app.js | 26 ++ itsm/static/favicon.ico | Bin 0 -> 17542 bytes itsm/static/icons/logo.png | Bin 0 -> 13388 bytes itsm/static/index.html | 59 ++- itsm/static/login.html | 263 +++++++++--- itsm/static/style.css | 120 +++++- manual/15_UI_Nifty_가이드.md | 290 +++++++++++++ 22 files changed, 3695 insertions(+), 61 deletions(-) create mode 100644 itsm/core/compliance_check.py create mode 100644 itsm/core/oauth.py create mode 100644 itsm/core/si_report.py create mode 100644 itsm/guardia_itsm.db.bak create mode 100644 itsm/routers/compliance.py create mode 100644 itsm/routers/deliverables.py create mode 100644 itsm/routers/jmeter.py create mode 100644 itsm/routers/public_checklist.py create mode 100644 itsm/routers/si_report.py create mode 100644 itsm/static/favicon.ico create mode 100644 itsm/static/icons/logo.png create mode 100644 manual/15_UI_Nifty_가이드.md diff --git a/itsm/core/compliance_check.py b/itsm/core/compliance_check.py new file mode 100644 index 00000000..8ad04375 --- /dev/null +++ b/itsm/core/compliance_check.py @@ -0,0 +1,291 @@ +""" +GUARDiA 준수성 자동 점검 엔진 + +1. 시큐어코딩 (행안부 SW 보안약점 기준 + OWASP Top 10) +2. 웹 접근성 (WCAG 2.1 / KWCAG 2.1 — 한국형) +3. 개인정보보호법 (PIPA — 개인정보 식별자 탐지) +""" +from __future__ import annotations + +import ast +import re +import os +import logging +from datetime import datetime +from pathlib import Path +from typing import Any + +logger = logging.getLogger(__name__) + +# ── 1. 시큐어코딩 점검 ─────────────────────────────────────────────────────── + +# 행안부 SW 보안약점 주요 패턴 +SECURE_CODING_RULES = [ + # SQL 인젝션 + { + "id": "SC-001", + "category": "SQL 인젝션", + "severity": "CRITICAL", + "pattern": r'execute\s*\(\s*f["\'].*\{|execute\s*\(\s*".*%.*%|execute\s*\(\s*\'.*\'\.format\(', + "message": "SQL 문자열 직접 포맷팅 — 파라미터 바인딩 사용 필요", + }, + # XSS + { + "id": "SC-002", + "category": "XSS", + "severity": "HIGH", + "pattern": r'innerHTML\s*=\s*(?!"|\')|\.html\s*\(', + "message": "innerHTML 직접 삽입 — textContent 또는 escapeHtml 함수 사용 필요", + }, + # 하드코딩 비밀번호/키 + { + "id": "SC-003", + "category": "하드코딩 자격증명", + "severity": "CRITICAL", + "pattern": r'(?i)(password|passwd|secret|api_key|apikey|token)\s*=\s*["\'][^"\']{6,}["\']', + "message": "하드코딩된 자격증명 — 환경변수 또는 시크릿 관리자 사용 필요", + }, + # OS 명령어 인젝션 + { + "id": "SC-004", + "category": "OS 명령어 인젝션", + "severity": "CRITICAL", + "pattern": r'os\.system\s*\(|subprocess\.call\s*\(.*shell\s*=\s*True|eval\s*\(', + "message": "shell=True 또는 eval 사용 — 입력값 검증 필수", + }, + # 경로 조작 + { + "id": "SC-005", + "category": "경로 조작", + "severity": "HIGH", + "pattern": r'open\s*\(\s*.*\+|open\s*\(\s*f["\']', + "message": "사용자 입력 기반 파일 경로 — Path.resolve().relative_to() 검증 필수", + }, + # 정보 노출 + { + "id": "SC-006", + "category": "민감 정보 노출", + "severity": "MEDIUM", + "pattern": r'traceback\.print_exc\(\)|print\s*\(.*exception|logger\.(info|debug).*password', + "message": "예외 스택트레이스 직접 출력 — 상세 오류 메시지 은닉 필요", + }, + # CSRF 위험 (GET으로 상태 변경) + { + "id": "SC-007", + "category": "CSRF", + "severity": "MEDIUM", + "pattern": r'@router\.get\s*\([^\)]+\)\s*\nasync def.*(delete|remove|drop|truncate)', + "message": "GET 메서드로 데이터 변경 — POST/DELETE 사용 및 CSRF 토큰 적용 필요", + }, + # 취약한 암호화 + { + "id": "SC-008", + "category": "취약 암호화", + "severity": "HIGH", + "pattern": r'md5|sha1\s*\(|DES\.|RC4\.', + "message": "취약한 해시/암호화 알고리즘 — SHA-256 이상 또는 AES-256-GCM 사용 필요", + }, +] + +# ── 2. 웹 접근성 점검 (HTML 기반) ──────────────────────────────────────────── + +ACCESSIBILITY_RULES = [ + { + "id": "WA-001", + "category": "대체 텍스트", + "level": "A", + "pattern": r']*alt=)[^>]*>', + "message": "img 요소에 alt 속성 없음 — 시각 장애인 스크린리더 접근 불가", + }, + { + "id": "WA-002", + "category": "색상 대비", + "level": "AA", + "pattern": r'color:\s*#(?:aaa|999|bbb|ccc|ddd|eee|f{3,6})', + "message": "낮은 색상 대비 — 4.5:1 이상 비율 필요 (WCAG 2.1 AA)", + }, + { + "id": "WA-003", + "category": "키보드 접근성", + "level": "A", + "pattern": r'onclick="[^"]*"(?![^>]*tabindex)', + "message": "onclick만 있는 요소 — tabindex + onkeydown 추가 또는 + + + + + +
+ +
+ 🔔 0 +
+ +
+ + + +
+
+ +``` + +--- + +## 6. 페이지 탭 (서브페이지 내부 탭) + +```html + +
+ + + + + + +
+
+
...
+
...
+ ... +
+``` + +```css +.page-tabs { + display: flex; gap: 2px; border-bottom: 2px solid var(--border); + margin-bottom: 20px; overflow-x: auto; +} +.page-tab { + padding: 10px 20px; background: none; border: none; + color: var(--text-muted); font-size: 13px; font-weight: 600; + cursor: pointer; border-bottom: 3px solid transparent; + margin-bottom: -2px; white-space: nowrap; +} +.page-tab.active { color: var(--accent); border-bottom-color: var(--accent); } +.tab-panel { display: none; } +.tab-panel.active { display: block; } +``` + +--- + +## 7. 카드 컴포넌트 + +```html + +
+
+

📊 프로젝트 현황

+
+ +
+
+
+ +
+
+``` + +--- + +## 8. 반응형 브레이크포인트 + +| 해상도 | 사이드바 | 레이아웃 | +|--------|---------|---------| +| ≥1280px | 250px 고정 | 2열 그리드 가능 | +| 768~1280px | 60px (아이콘만) | 1열 | +| < 768px | 오버레이 (토글) | 모바일 전용 | + +--- + +## 9. 적용 우선순위 + +1. **즉시 적용**: 탑바 + 사이드바 아코디언 메뉴 (`index.html` + `style.css`) +2. **1주일 내**: PMS 서브탭 페이지 (`si.html` 확장) +3. **2주 내**: 보안/모니터링 전용 페이지 UI 통일 + +--- + +## 10. Copyright 표기 위치 + +- **사이드바 하단**: `Copyright © 2026 GUARDiA All Rights Reserved.` +- **로그인 페이지**: 로고 이미지 + Copyright +- **출력 보고서**: 모든 Excel/PDF/PPTX 하단 +- **API 응답 헤더**: `X-Powered-By: GUARDiA ITSM 2.0` + +```python +# FastAPI 미들웨어로 응답 헤더 추가 +@app.middleware("http") +async def add_copyright_header(request, call_next): + response = await call_next(request) + response.headers["X-Powered-By"] = "GUARDiA ITSM 2.0 | Copyright 2026" + return response +```