Fix section mapping for security rules

- Replace React performance section map with security categories (1-28)
- Fix _sections.md parsing to use ### headings instead of ##
- Each rule now maps to its proper section by filename

Now generates 28 sections organized by impact level:
- Critical (1-9): SQL injection, XSS, secrets, etc.
- High (10-22): Crypto, SSRF, Terraform, K8s, etc.
- Medium (23-25): Regex DoS, race conditions
- Low (26-28): Best practices, performance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Drew Dennison
2026-01-15 14:14:33 -08:00
parent 2e12e64d4d
commit bfa8941893
4 changed files with 3041 additions and 2772 deletions
+5 -4
View File
@@ -177,15 +177,16 @@ async function build() {
try {
const sectionsContent = await readFile(sectionsFile, 'utf-8')
// Parse sections using regex to match each section block
// Parse sections using regex to match each section block (uses ### headings)
const sectionBlocks = sectionsContent
.split(/(?=^## \d+\. )/m)
.split(/(?=^### \d+\. )/m)
.filter(Boolean)
for (const block of sectionBlocks) {
// Extract section number and title, removing section ID in parentheses
// Format: ### 1. SQL Injection (sql-injection)
const headerMatch = block.match(
/^## (\d+)\.\s+(.+?)(?:\s+\([^)]+\))?$/m
/^### (\d+)\.\s+(.+?)(?:\s+\([^)]+\))?$/m
)
if (!headerMatch) continue
@@ -200,7 +201,7 @@ async function build() {
// Extract description (format: **Description:** text)
const descMatch = block.match(
/\*\*Description:\*\*\s+(.+?)(?=\n\n##|$)/s
/\*\*Description:\*\*\s+(.+?)(?=\n\n###|\n\n---|$)/s
)
const description = descMatch ? descMatch[1].trim() : ''
+35 -12
View File
@@ -213,21 +213,44 @@ export async function parseRuleFile(filePath: string): Promise<RuleFile> {
examples.push(currentExample)
}
// Infer section from filename patterns
const filename = filePath.split('/').pop() || ''
// Map filename to section number based on _sections.md ordering
const filename = filePath.split('/').pop()?.replace('.md', '') || ''
const sectionMap: Record<string, number> = {
async: 1,
bundle: 2,
server: 3,
client: 4,
rerender: 5,
rendering: 6,
js: 7,
advanced: 8,
// Critical Impact (1-9)
'sql-injection': 1,
'command-injection': 2,
'xss': 3,
'xxe': 4,
'path-traversal': 5,
'insecure-deserialization': 6,
'code-injection': 7,
'secrets': 8,
'memory-safety': 9,
// High Impact (10-22)
'insecure-crypto': 10,
'insecure-transport': 11,
'ssrf': 12,
'authentication-jwt': 13,
'csrf': 14,
'prototype-pollution': 15,
'unsafe-functions': 16,
'terraform-aws': 17,
'terraform-azure': 18,
'terraform-gcp': 19,
'kubernetes': 20,
'docker': 21,
'github-actions': 22,
// Medium Impact (23-25)
'regex-dos': 23,
'race-condition': 24,
'correctness': 25,
// Low Impact (26-28)
'best-practice': 26,
'performance': 27,
'maintainability': 28,
}
const area = filename.split('-')[0]
const section = frontmatter.section || sectionMap[area] || 0
const section = frontmatter.section || sectionMap[filename] || 0
const rule: Rule = {
id: '', // Will be assigned by build script based on sorted order
Binary file not shown.
File diff suppressed because it is too large Load Diff