Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0f26941
Add Lint & format workflows.
Einswilli Sep 6, 2025
40e02aa
Merge branch 'AllDotPy:master' into master
Einswilli Sep 6, 2025
b9913ca
Add Code of Conduct.
Einswilli Sep 6, 2025
b6bd262
Add Contributions guide.
Einswilli Sep 6, 2025
f9dfa45
Merge branch 'master' of https://github.com/Einswilli/Valkyrie
Einswilli Sep 6, 2025
1afc3a0
Update CONTRUBUTING.md and Pyproject.toml files.
Einswilli Sep 6, 2025
30d578c
Update CONTRUBUTING.md and Pyproject.toml files.
Einswilli Sep 6, 2025
f1b4428
remove main.py file form the root dir.
Einswilli Sep 6, 2025
850e5d7
Merge branch 'AllDotPy:master' into master
Einswilli Sep 6, 2025
d6e7800
valkyrie.core: Add Scanner engine and types modules.
Einswilli Sep 6, 2025
dbaee48
feat(core): Add Scanner Configuration types and Scanner Engine.
Einswilli Sep 6, 2025
7df00ad
Merge branch 'AllDotPy:master' into master
Einswilli Sep 6, 2025
6c125cf
valkyrie.plugins: Add Security Rules Base class Secrets detector Plugin.
Einswilli Sep 7, 2025
b6c7d6c
__ # Merge branch 'master' of https://github.com/Einswilli/Valkyrie i…
Einswilli Sep 7, 2025
1ba0352
valkyrie.plugins: Add Plugin manager.
Einswilli Sep 7, 2025
d023343
valkyrie.plugins: Add Plugin manager.
Einswilli Sep 7, 2025
a2fef8b
valkyrie.plugins: Add Plugin manager.
Einswilli Sep 7, 2025
e90ba68
Merge branch 'AllDotPy:master' into master
Einswilli Sep 7, 2025
73474ef
valkyrie.plugins: Add Plugin manager.
Einswilli Sep 7, 2025
e1238c4
valkyrie.plugins: Add Plugin manager.
Einswilli Sep 7, 2025
4bfa0fa
Merge branch 'AllDotPy:master' into master
Einswilli Sep 7, 2025
e3b808a
Merge branch 'AllDotPy:master' into feat.plugins
Einswilli Sep 7, 2025
ae14c1d
Feat (plugins): Add Plugin manager
Einswilli Sep 7, 2025
f0310b4
refractor: valkyrie.plugins.secrets.
Einswilli Sep 8, 2025
ebb3a38
Merge branch 'AllDotPy:master' into master
Einswilli Sep 8, 2025
d9677d4
Merge branch 'AllDotPy:master' into feat.plugins
Einswilli Sep 8, 2025
a49198d
Merge branch 'master' into feat.plugins
Einswilli Sep 8, 2025
cf596f8
Merge branch into feat.plugins
Einswilli Sep 8, 2025
e071c5f
Merge branch 'master' into feat.plugins
Einswilli Sep 8, 2025
ce522fa
Refractor: Refractor secrets plugin to make it more cleanner.
Einswilli Sep 8, 2025
d716401
Merge branch 'AllDotPy:master' into master
Einswilli Sep 8, 2025
f405674
valkyrie,plugins: add vulnera vulnerablity scanner plugin
Einswilli Sep 11, 2025
bdc5a04
valkyrie,plugins: Fix typo in Vulnera.parser
Einswilli Sep 11, 2025
a35a54e
Merge branch 'AllDotPy:master' into master
Einswilli Sep 11, 2025
fd7fb9f
valkkyrie.plugins: Add iamx plugin foor IAM configuration Scanning
Einswilli Sep 12, 2025
46c4453
valkkyrie.plugins: Add iamx plugin foor IAM configuration Scanning
Einswilli Sep 12, 2025
a288bae
Valkyrie.core: Add Scann Result Formatters base class and SARIF Formm…
Einswilli Sep 13, 2025
a97b666
Merge branch 'AllDotPy:master' into master
Einswilli Sep 13, 2025
1e6b5b9
Merge branch 'master' of https://github.com/Einswilli/Valkyrie into f…
Einswilli Sep 13, 2025
312124c
Merge branch 'AllDotPy:master' into master
Einswilli Sep 13, 2025
1ad6ec1
Valkyrie.core: Add HTML Scann Result Formmater
Einswilli Sep 13, 2025
50d4406
Merge branch 'master' of https://github.com/Einswilli/Valkyrie into f…
Einswilli Sep 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions valkyrie/core/formatters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .base import ResultFormatter
from .sarif import SARIFFormatter

__all__ = [
ResultFormatter,
SARIFFormatter
]
134 changes: 134 additions & 0 deletions valkyrie/core/formatters/html.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
"""
Valkyrie - HTML Scan Result Formatter
"""

from valkyrie.core.types import (
SeverityLevel, ScanResult, ScanStatus
)

from .base import ResultFormatter


####
## HTML SCAN RESUT FORMATTER
#####
class HTMLFormatter(ResultFormatter):
"""HTML report formatter"""

def format(self, result: ScanResult) -> str:
"""Format results as HTML report"""

html = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Valkyrie Security Scan Report</title>
<style>
body {{ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }}
.container {{ max-width: 1200px; margin: 0 auto; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
.header {{ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 8px 8px 0 0; }}
.content {{ padding: 30px; }}
.summary {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; }}
.metric {{ background: #f8f9fa; padding: 20px; border-radius: 8px; text-align: center; border-left: 4px solid #667eea; }}
.critical {{ border-left-color: #dc3545; }}
.high {{ border-left-color: #fd7e14; }}
.medium {{ border-left-color: #ffc107; }}
.low {{ border-left-color: #28a745; }}
.finding {{ border: 1px solid #dee2e6; border-radius: 8px; margin-bottom: 15px; }}
.finding-header {{ padding: 15px; background: #f8f9fa; border-bottom: 1px solid #dee2e6; }}
.finding-body {{ padding: 15px; }}
.severity-badge {{ display: inline-block; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: bold; text-transform: uppercase; }}
.severity-critical {{ background: #dc3545; color: white; }}
.severity-high {{ background: #fd7e14; color: white; }}
.severity-medium {{ background: #ffc107; color: black; }}
.severity-low {{ background: #28a745; color: white; }}
.severity-info {{ background: #17a2b8; color: white; }}
.file-location {{ font-family: monospace; background: #f8f9fa; padding: 4px 8px; border-radius: 4px; }}
.no-findings {{ text-align: center; padding: 60px; color: #6c757d; }}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🛡️ Valkyrie Security Scan Report</h1>
<p>Scan completed on {result.timestamp.strftime('%Y-%m-%d %H:%M:%S')}</p>
<p>Duration: {result.scan_duration:.2f}s | Files scanned: {len(result.scanned_files)}</p>
</div>

<div class="content">
{self._generate_summary_html(result)}
{self._generate_findings_html(result)}
</div>
</div>
</body>
</html>
"""
return html

def _generate_summary_html(self, result: ScanResult) -> str:
"""Generate summary section HTML"""

if result.status == ScanStatus.FAILED:
return '<div class="summary"><div class="metric critical"><h3>❌ Scan Failed</h3><p>Check logs for details</p></div></div>'

return f"""
<div class="summary">
<div class="metric">
<h3>{len(result.findings)}</h3>
<p>Total Issues</p>
</div>
<div class="metric critical">
<h3>{result.critical_count}</h3>
<p>Critical</p>
</div>
<div class="metric high">
<h3>{result.high_count}</h3>
<p>High</p>
</div>
<div class="metric medium">
<h3>{sum(1 for f in result.findings if f.severity == SeverityLevel.MEDIUM)}</h3>
<p>Medium</p>
</div>
<div class="metric low">
<h3>{sum(1 for f in result.findings if f.severity == SeverityLevel.LOW)}</h3>
<p>Low</p>
</div>
</div>
"""

def _generate_findings_html(self, result: ScanResult) -> str:
"""Generate findings section HTML"""

if not result.findings:
return '<div class="no-findings"><h2>✅ No security issues found!</h2><p>All scanned files are secure.</p></div>'

html = "<h2>Security Findings</h2>"

# Sort findings by severity
sorted_findings = sorted(result.findings, key=lambda f: [
SeverityLevel.CRITICAL, SeverityLevel.HIGH, SeverityLevel.MEDIUM,
SeverityLevel.LOW, SeverityLevel.INFO
].index(f.severity))

for finding in sorted_findings:
severity_class = f"severity-{finding.severity.value}"
html += f"""
<div class="finding">
<div class="finding-header">
<span class="severity-badge {severity_class}">{finding.severity.value}</span>
<strong>{finding.title}</strong>
<div style="float: right;">
<span class="file-location">{finding.location.file_path}:{finding.location.line_number}</span>
</div>
</div>
<div class="finding-body">
<p>{finding.description}</p>
{f'<p><strong>Remediation:</strong> {finding.remediation_advice}</p>' if finding.remediation_advice else ''}
<p><strong>Rule ID:</strong> {finding.rule_id} | <strong>Confidence:</strong> {finding.confidence:.1%}</p>
</div>
</div>
"""

return html