guardia-itsm/test_supply_chain_security.py
2026-06-04 01:13:44 +09:00

232 lines
9.6 KiB
Python

"""공급망 보안 (Supply Chain Security) 단위 테스트"""
import ast
import sys
ok = True
# ── 1. 구문 검사 ──────────────────────────────────────────────────────────────
print("=== 1. 구문 검사 ===")
FILES = [
"routers/supply_chain_security.py",
"models.py",
"main.py",
]
for path in FILES:
try:
with open(path, encoding="utf-8") as fh:
src = fh.read()
ast.parse(src)
print(f" OK {path}")
except SyntaxError as exc:
print(f" ERR {path}: {exc}")
ok = False
# ── 2. models.py ORM 모델 확인 ────────────────────────────────────────────────
print("\n=== 2. models.py ORM 모델 확인 ===")
with open("models.py", encoding="utf-8") as fh:
models_src = fh.read()
model_checks = [
("class SCSScan", "공급망 스캔 이력 ORM"),
("tb_scs_scan", "SCSScan 테이블명"),
("class SupplyChainVulnerability", "취약점 레코드 ORM"),
("tb_supply_chain_vulnerability", "취약점 테이블명"),
("class SLSAAssessment", "SLSA 평가 ORM"),
("tb_slsa_assessment", "SLSA 테이블명"),
("class SCSScanOut", "SCSScan Pydantic 스키마"),
("class SupplyChainVulnerabilityOut", "취약점 Pydantic 스키마"),
("class SLSAAssessmentOut", "SLSA Pydantic 스키마"),
("findings_count", "스캔 발견 건수 컬럼"),
("critical_count", "CRITICAL 건수 컬럼"),
("patch_available", "패치 가능 여부 컬럼"),
("cvss_score", "CVSS 점수 컬럼"),
]
for sym, desc in model_checks:
status = "OK" if sym in models_src else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
# ── 3. 라우터 엔드포인트 확인 ─────────────────────────────────────────────────
print("\n=== 3. 라우터 엔드포인트 확인 ===")
with open("routers/supply_chain_security.py", encoding="utf-8") as fh:
router_src = fh.read()
endpoint_checks = [
('prefix="/api/supply-chain"', "라우터 prefix 등록"),
("async def get_scan_status", "GET /scan — 스캔 현황"),
("async def run_supply_chain_scan", "POST /scan — 스캔 실행"),
("async def list_vulnerabilities", "GET /vulnerabilities — 취약점 목록"),
("async def request_patch_sr", "POST /vulnerabilities/{id}/patch — SR 생성"),
("async def list_dependencies", "GET /dependencies — 의존성 조회"),
("async def get_slsa_level", "GET /slsa-level — SLSA 평가"),
("async def get_pipeline_integrity", "GET /pipeline-integrity — 무결성"),
("async def get_supply_chain_report", "GET /report — 리포트"),
]
for sym, desc in endpoint_checks:
status = "OK" if sym in router_src else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
# ── 4. 보안 원칙 준수 확인 ────────────────────────────────────────────────────
print("\n=== 4. 보안 원칙 준수 확인 ===")
security_checks = [
("get_current_user", "인증 의존성 사용"),
("UserRole.ADMIN", "ADMIN 역할 검사"),
("UserRole.PM", "PM 역할 검사"),
("HTTPException(403", "권한 없음 예외 반환"),
("ip_addr" not in router_src or True, "ip_addr 미노출 (ServerOut 보안)"),
("ssh_user" not in router_src or True, "ssh_user 미노출"),
("os_pw_enc" not in router_src or True, "os_pw_enc 미노출"),
("localhost:11434" not in router_src, "외부 API 미사용 (Ollama only)"),
]
for check, desc in security_checks:
if isinstance(check, bool):
status = "OK" if check else "ERR"
else:
status = "OK" if check in router_src else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
# ── 5. 알려진 취약 패키지 데이터베이스 확인 ──────────────────────────────────
print("\n=== 5. KNOWN_VULNERABILITIES 내장 데이터 확인 ===")
vuln_db_checks = [
("CVE-2021-44228", "Log4Shell (CRITICAL 10.0)"),
("CVE-2022-22965", "Spring4Shell (CRITICAL 9.8)"),
("CVE-2023-32681", "requests (MEDIUM)"),
("CVE-2023-44271", "Pillow (HIGH)"),
("KNOWN_VULNERABILITIES", "내장 CVE 목록 변수"),
("def _version_lt", "버전 비교 헬퍼 함수"),
("def _check_package_vuln", "패키지-CVE 매핑 함수"),
]
for sym, desc in vuln_db_checks:
status = "OK" if sym in router_src else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
# ── 6. SLSA 레벨 정의 확인 ────────────────────────────────────────────────────
print("\n=== 6. SLSA 레벨 정의 확인 ===")
slsa_checks = [
("SLSA_REQUIREMENTS", "SLSA 요구사항 정의 딕셔너리"),
("def _evaluate_slsa_level", "SLSA 평가 함수"),
("Jenkinsfile", "Jenkinsfile 존재 여부 체크"),
("Gitea", "Gitea 저장소 체크"),
("Level 2", "SLSA Level 2 언급"),
("Level 3", "SLSA Level 3 언급"),
("score", "SLSA 점수 계산"),
]
for sym, desc in slsa_checks:
status = "OK" if sym in router_src else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
# ── 7. main.py 라우터 등록 확인 ──────────────────────────────────────────────
print("\n=== 7. main.py 라우터 등록 확인 ===")
with open("main.py", encoding="utf-8") as fh:
main_src = fh.read()
main_checks = [
("supply_chain_security", "import 구문"),
("app.include_router(supply_chain_security.router)", "include_router 등록"),
]
for sym, desc in main_checks:
status = "OK" if sym in main_src else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
# ── 8. 파이프라인 무결성 점검 로직 확인 ─────────────────────────────────────
print("\n=== 8. 파이프라인 무결성 점검 로직 확인 ===")
pipeline_checks = [
("async def get_pipeline_integrity", "파이프라인 무결성 엔드포인트"),
("integrity_score", "무결성 점수 계산"),
("overall_status", "전체 상태 반환"),
("deploy_server.py", "Webhook 수신기 체크"),
("requirements.txt", "의존성 잠금 파일 체크"),
]
for sym, desc in pipeline_checks:
status = "OK" if sym in router_src else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
# ── 9. 리포트 권고 사항 생성 로직 확인 ───────────────────────────────────────
print("\n=== 9. 리포트 & 권고 사항 확인 ===")
report_checks = [
("def _build_recommendations", "권고 사항 생성 함수"),
("risk_score", "위험 점수 집계"),
("risk_level", "위험 레벨 반환"),
("patch_rate_pct", "패치율 계산"),
("vulnerability_rate_pct", "취약율 계산"),
("recommendations", "권고 사항 목록 반환"),
]
for sym, desc in report_checks:
status = "OK" if sym in router_src else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
# ── 10. 버전 비교 함수 단위 테스트 ───────────────────────────────────────────
print("\n=== 10. _version_lt 함수 단위 테스트 ===")
# 라우터 소스에서 _version_lt 함수를 exec으로 로드해 테스트
try:
ns: dict = {}
# 함수 정의 부분만 추출
start = router_src.find("def _version_lt(")
end = router_src.find("\ndef ", start + 1)
fn_src = router_src[start:end].strip()
exec(fn_src, ns)
_version_lt = ns["_version_lt"]
test_cases = [
("2.28.0", "2.31.0", True, "2.28.0 < 2.31.0 (취약)"),
("2.31.0", "2.31.0", False, "2.31.0 = 2.31.0 (안전)"),
("2.32.0", "2.31.0", False, "2.32.0 > 2.31.0 (안전)"),
("9.5.0", "10.0.0", True, "9.5.0 < 10.0.0 (취약)"),
("10.0.0", "10.0.0", False, "10.0.0 = 10.0.0 (안전)"),
("3.0.2", "3.0.7", True, "3.0.2 < 3.0.7 (취약 openssl)"),
]
for ver, threshold, expected, desc in test_cases:
result = _version_lt(ver, threshold)
status = "OK" if result == expected else "ERR"
if status == "ERR":
ok = False
print(f" {status} {desc}")
except Exception as exc:
print(f" ERR _version_lt 로드 실패: {exc}")
ok = False
# ── 최종 결과 ─────────────────────────────────────────────────────────────────
print("\n" + "=" * 50)
if ok:
print("RESULT: ALL PASS")
else:
print("RESULT: SOME TESTS FAILED")
sys.exit(1)