웹 취약점 점검 툴 sonarQube 무료 pdf 출력 방법
Dec 2, 2025
»
backEnd
sonarQube 를 이용해 만든 데이터로 PDF 출력
과거 버전에서는 PDF 출력 기능을 지원하는것 같았으나, 현 시점에서는 지원하지 않음
그래서 sonarQube 데이터를 api 로 받아와 chrome 을 이용해 html 로 생성 후 pdf 로 만들 예정
ps 파일 생성
- 아래 복사 후 generate-report.ps1 파일명으로 저장
# ===============================
# SonarQube PDF Report Generator (Chunked)
# ===============================
$SonarHost = "http://localhost:9000"
$ProjectKey = "YOUR_PROJECT"
$Token = ""
$OutputPdfPrefix = "YOUR_PROJECT_Report_Page"
$HtmlFilePrefix = "YOUR_PROJECT_Report_Page"
# -----------------------------------
# HTML Escape Function
# -----------------------------------
function Escape-Html {
param([string]$text)
if (-not $text) { return "" }
return $text -replace '&','&' `
-replace '<','<' `
-replace '>','>' `
-replace '"','"' `
-replace "'","'"
}
# -----------------------------------
# 인증 정보
# -----------------------------------
$encodedAuth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($Token + ":"))
# -----------------------------------
# 1. Summary Metrics 조회
# -----------------------------------
$metricsUrl = "$SonarHost/api/measures/component?component=$ProjectKey&metricKeys=bugs,vulnerabilities,code_smells,coverage"
$summary = Invoke-RestMethod -Uri $metricsUrl -Headers @{Authorization="Basic $encodedAuth"}
$bugs = $summary.component.measures | Where-Object {$_.metric -eq "bugs"} | Select-Object -Expand value
$vuln = $summary.component.measures | Where-Object {$_.metric -eq "vulnerabilities"} | Select-Object -Expand value
$smells = $summary.component.measures | Where-Object {$_.metric -eq "code_smells"} | Select-Object -Expand value
$coverage = $summary.component.measures | Where-Object {$_.metric -eq "coverage"} | Select-Object -Expand value
if (-not $coverage) { $coverage = "N/A" }
# -----------------------------------
# 2. Issues 전체 조회 (10,000 단위)
# -----------------------------------
$allIssues = @()
$pageSize = 10000
$offset = 0
while ($true) {
$issuesUrl = "$SonarHost/api/issues/search?componentKeys=$ProjectKey&pageSize=$pageSize&p=$([math]::Floor($offset / $pageSize) + 1)"
$pagedData = Invoke-RestMethod -Uri $issuesUrl -Headers @{Authorization="Basic $encodedAuth"}
if (-not $pagedData.issues -or $pagedData.issues.Count -eq 0) {
Write-Host "No more issues to load. Exiting..."
break
}
$allIssues += $pagedData.issues
Write-Host "Loaded $($pagedData.issues.Count) issues (Total: $($allIssues.Count))"
$offset += $pagedData.issues.Count
if ($offset -ge $pagedData.paging.total) { break }
}
$issuesData = [PSCustomObject]@{ issues = $allIssues }
# -----------------------------------
# 3. Chunk 단위로 HTML/PDF 생성
# -----------------------------------
$chunkSize = 1000 # 1파일당 1000건
$totalIssues = $issuesData.issues.Count
$pageCount = [math]::Ceiling($totalIssues / $chunkSize)
$chromePath = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
for ($i = 0; $i -lt $pageCount; $i++) {
$start = $i * $chunkSize
$end = [math]::Min($start + $chunkSize - 1, $totalIssues - 1)
$chunkIssues = $issuesData.issues[$start..$end]
$HtmlFile = "$HtmlFilePrefix$($i+1).html"
$OutputPdf = "$OutputPdfPrefix$($i+1).pdf"
# HTML 생성
$html = @"
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>YOUR PROJECT Report Page $($i+1)</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f8f9fa; padding: 20px; }
h1 { color: #0d6efd; } h2 { color: #495057; margin-top:40px; }
.summary-card { background: white; padding: 20px; border-radius: 10px; margin-bottom: 30px; box-shadow: 0 3px 8px rgba(0,0,0,0.1); }
table { width: 100%; border-collapse: collapse; margin-top: 15px; }
th, td { border: 1px solid #dee2e6; padding: 8px 10px; font-size: 14px; }
th { background-color: #0d6efd; color: white; }
tr:nth-child(even) { background: #f1f3f5; }
.severity-BLOCKER { background:#dc3545 !important; color:white !important; }
.severity-CRITICAL { background:#fd7e14 !important; color:white !important; }
.severity-MAJOR { background:#ffc107 !important; color:black !important; }
.severity-MINOR { background:#198754 !important; color:white !important; }
.severity-INFO { background:#0dcaf0 !important; color:black !important; }
.chart-container { width: 400px; height: 300px; margin-top:20px; }
</style>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<h1>SonarQube Project Report - Page $($i+1)</h1>
<p>Generated: $(Get-Date)</p>
<div class="summary-card">
<h2>Summary</h2>
<table>
<tr><th>Metric</th><th>Value</th></tr>
<tr><td>Bugs</td><td>$bugs</td></tr>
<tr><td>Vulnerabilities</td><td>$vuln</td></tr>
<tr><td>Code Smells</td><td>$smells</td></tr>
<tr><td>Coverage</td><td>$coverage %</td></tr>
</table>
</div>
<h2>Issues Detail</h2>
<table>
<tr><th>Type</th><th>Severity</th><th>Message</th><th>File</th><th>Line</th></tr>
"@
foreach ($issue in $chunkIssues) {
$type = Escape-Html $issue.type
$sev = Escape-Html $issue.severity
$msg = Escape-Html $issue.message
$file = Escape-Html $issue.component
$line = Escape-Html $issue.line
$sevClass = "severity-$sev"
$html += "<tr class='$sevClass'><td>$type</td><td>$sev</td><td>$msg</td><td>$file</td><td>$line</td></tr>"
}
$html += "</table></body></html>"
# HTML 파일 저장
$html | Out-File -Encoding utf8 $HtmlFile
Write-Host "Generated HTML: $HtmlFile"
# PDF 변환
Start-Process $chromePath "--headless --disable-gpu --print-to-pdf=$OutputPdf $HtmlFile" -Wait
Write-Host "Generated PDF: $OutputPdf"
}
Write-Host "All pages generated: $pageCount pages."
report 출력
- PowerShell 관리자 권한 으로 실행
- 저장 한 파일 위치로 이동 및 아래 명령어 실행
cd /설치_경로 powershell -ExecutionPolicy Bypass -File generate-report.ps1