mirror of
https://github.com/projectdiscovery/nuclei-templates.git
synced 2026-01-31 07:43:27 +08:00
120 lines
3.4 KiB
Python
Executable File
120 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Count KEV and vKEV templates for README statistics
|
|
|
|
This script counts the number of templates with 'kev' and 'vkev' tags
|
|
and outputs the statistics in a format suitable for the README.
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Dict, Set
|
|
|
|
|
|
def has_tag_in_file(file_path: Path, tag: str) -> bool:
|
|
"""Check if a template file has a specific tag."""
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
# Look for tags field and check if tag is present
|
|
tags_match = re.search(r'tags:\s*([^\n]+)', content)
|
|
if tags_match:
|
|
tags_str = tags_match.group(1)
|
|
# Check for tag as a standalone tag (not part of another word)
|
|
if re.search(rf'\b{tag}\b', tags_str, re.IGNORECASE):
|
|
return True
|
|
except Exception as e:
|
|
print(f"Error reading {file_path}: {e}", file=sys.stderr)
|
|
|
|
return False
|
|
|
|
|
|
def count_kev_templates(root_dir: str) -> Dict[str, int]:
|
|
"""Count templates with KEV and vKEV tags."""
|
|
root_path = Path(root_dir)
|
|
|
|
# Find all YAML template files
|
|
patterns = [
|
|
"**/*.yaml",
|
|
"**/*.yml"
|
|
]
|
|
|
|
all_files = set()
|
|
for pattern in patterns:
|
|
all_files.update(root_path.glob(pattern))
|
|
|
|
# Filter out non-template files
|
|
template_files = [
|
|
f for f in all_files
|
|
if '/workflows/' not in str(f)
|
|
and '/.github/' not in str(f)
|
|
and '/profiles/' not in str(f)
|
|
]
|
|
|
|
kev_count = 0
|
|
vkev_count = 0
|
|
both_count = 0
|
|
kev_only_count = 0
|
|
vkev_only_count = 0
|
|
|
|
kev_files = set()
|
|
vkev_files = set()
|
|
|
|
for template_file in template_files:
|
|
has_kev = has_tag_in_file(template_file, 'kev')
|
|
has_vkev = has_tag_in_file(template_file, 'vkev')
|
|
|
|
if has_kev:
|
|
kev_count += 1
|
|
kev_files.add(template_file)
|
|
|
|
if has_vkev:
|
|
vkev_count += 1
|
|
vkev_files.add(template_file)
|
|
|
|
if has_kev and has_vkev:
|
|
both_count += 1
|
|
elif has_kev:
|
|
kev_only_count += 1
|
|
elif has_vkev:
|
|
vkev_only_count += 1
|
|
|
|
return {
|
|
'kev_total': kev_count,
|
|
'vkev_total': vkev_count,
|
|
'both': both_count,
|
|
'kev_only': kev_only_count,
|
|
'vkev_only': vkev_only_count,
|
|
'total_templates': len(template_files)
|
|
}
|
|
|
|
|
|
def main():
|
|
"""Main entry point."""
|
|
root_dir = sys.argv[1] if len(sys.argv) > 1 else '.'
|
|
|
|
stats = count_kev_templates(root_dir)
|
|
|
|
# Output in a format that can be easily parsed
|
|
print(f"KEV_TOTAL={stats['kev_total']}")
|
|
print(f"VKEV_TOTAL={stats['vkev_total']}")
|
|
print(f"BOTH={stats['both']}")
|
|
print(f"KEV_ONLY={stats['kev_only']}")
|
|
print(f"VKEV_ONLY={stats['vkev_only']}")
|
|
print(f"TOTAL_TEMPLATES={stats['total_templates']}")
|
|
|
|
# Also print human-readable summary to stderr for logging
|
|
print("\n=== KEV/vKEV Statistics ===", file=sys.stderr)
|
|
print(f"CISA KEV templates: {stats['kev_total']}", file=sys.stderr)
|
|
print(f"VulnCheck KEV templates: {stats['vkev_total']}", file=sys.stderr)
|
|
print(f"Templates in both: {stats['both']}", file=sys.stderr)
|
|
print(f"CISA KEV only: {stats['kev_only']}", file=sys.stderr)
|
|
print(f"VulnCheck KEV only: {stats['vkev_only']}", file=sys.stderr)
|
|
print(f"Total templates scanned: {stats['total_templates']}", file=sys.stderr)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|