From 1f8b926066b6b8b2b17f2fe3d7a62a4c5f3b9033 Mon Sep 17 00:00:00 2001 From: DESKTOP-TKLFCPRython 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 --- core/compliance_check.py | 291 +++++++++++++++ core/oauth.py | 199 +++++++++++ core/scheduler.py | 76 ++++ core/si_report.py | 683 ++++++++++++++++++++++++++++++++++++ guardia_itsm.db.bak | Bin 0 -> 933888 bytes main.py | 28 +- models.py | 98 ++++++ requirements.txt | 6 + routers/auth.py | 92 +++++ routers/compliance.py | 229 ++++++++++++ routers/deliverables.py | 263 ++++++++++++++ routers/jmeter.py | 431 +++++++++++++++++++++++ routers/public_checklist.py | 354 +++++++++++++++++++ routers/si_issues.py | 59 ++++ routers/si_report.py | 189 ++++++++++ static/app.js | 26 ++ static/favicon.ico | Bin 0 -> 17542 bytes static/icons/logo.png | Bin 0 -> 13388 bytes static/index.html | 59 +++- static/login.html | 263 +++++++++++--- static/style.css | 120 ++++++- 21 files changed, 3405 insertions(+), 61 deletions(-) create mode 100644 core/compliance_check.py create mode 100644 core/oauth.py create mode 100644 core/si_report.py create mode 100644 guardia_itsm.db.bak create mode 100644 routers/compliance.py create mode 100644 routers/deliverables.py create mode 100644 routers/jmeter.py create mode 100644 routers/public_checklist.py create mode 100644 routers/si_report.py create mode 100644 static/favicon.ico create mode 100644 static/icons/logo.png diff --git a/core/compliance_check.py b/core/compliance_check.py new file mode 100644 index 0000000..8ad0437 --- /dev/null +++ b/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 추가 또는