226 lines
9.6 KiB
JSON
226 lines
9.6 KiB
JSON
{
|
|
"$schema": "../../.guardrails/prevention-rules/semantic-rules.schema.json",
|
|
"description": "Example semantic/AST-based prevention rules for complex regression detection. These analyze code structure, not just text patterns. All examples are DISABLED.",
|
|
"version": "1.0.0",
|
|
"rules": [
|
|
{
|
|
"rule_id": "SEMANTIC-EX-001",
|
|
"failure_id": "FAIL-WEB-001",
|
|
"name": "Unhandled promise in async function",
|
|
"description": "Detects async functions that don't await promises or handle rejections. Based on FAIL-WEB-001 where unhandled promise rejection caused crash.",
|
|
"enabled": false,
|
|
"language": "javascript",
|
|
"ast_pattern": {
|
|
"type": "FunctionDeclaration|FunctionExpression|ArrowFunctionExpression",
|
|
"async": true,
|
|
"body": {
|
|
"contains": {
|
|
"type": "CallExpression",
|
|
"callee": {
|
|
"type": "MemberExpression|Identifier"
|
|
},
|
|
"awaited": false,
|
|
"returnsPromise": true
|
|
}
|
|
}
|
|
},
|
|
"message": "ASYNC BUG RISK: Promise returned but not awaited in async function. Based on FAIL-WEB-001 where unhandled promise caused unexpected behavior.",
|
|
"severity": "error",
|
|
"suggestion": "Add await keyword: const result = await fetchData(); or handle with .catch(): fetchData().catch(handleError);"
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-002",
|
|
"failure_id": "FAIL-UI-001",
|
|
"name": "File opened without context manager",
|
|
"description": "Detects file operations that don't use 'with' statement in Python. Based on resource leak patterns.",
|
|
"enabled": false,
|
|
"language": "python",
|
|
"ast_pattern": {
|
|
"type": "Assign",
|
|
"targets": [{
|
|
"type": "Name"
|
|
}],
|
|
"value": {
|
|
"type": "Call",
|
|
"func": {
|
|
"type": "Name",
|
|
"id": "open"
|
|
}
|
|
},
|
|
"not_within": "with"
|
|
},
|
|
"message": "RESOURCE LEAK: File opened without context manager. File may not be closed on exception. Based on FAIL-UI-001 resource leak pattern.",
|
|
"severity": "warning",
|
|
"suggestion": "Use context manager: with open('file.txt') as f: data = f.read()"
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-003",
|
|
"failure_id": "FAIL-AUTH-001",
|
|
"name": "Route without authentication decorator",
|
|
"description": "Detects Flask/FastAPI/Django route handlers that are missing authentication decorators. Based on security vulnerability where endpoint was left unprotected.",
|
|
"enabled": false,
|
|
"language": "python",
|
|
"ast_pattern": {
|
|
"type": "FunctionDef",
|
|
"decorators": {
|
|
"contains_any": ["@app.route", "@router.get", "@router.post", "@api_view"],
|
|
"missing_all": ["@login_required", "@require_auth", "@jwt_required", "@permission_classes"]
|
|
},
|
|
"excluded_decorators": ["@public", "@no_auth", "@allow_anonymous"]
|
|
},
|
|
"message": "SECURITY: Route handler missing authentication decorator. Based on FAIL-AUTH-001 where unprotected endpoint exposed sensitive data.",
|
|
"severity": "error",
|
|
"suggestion": "Add authentication: @login_required or @require_auth decorator, or explicitly mark as public with @public decorator if intentional"
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-004",
|
|
"failure_id": "FAIL-DB-002",
|
|
"name": "Database transaction without rollback handler",
|
|
"description": "Detects database transactions that don't have proper exception handling with rollback. Based on FAIL-DB-002 where failed transaction left database in inconsistent state.",
|
|
"enabled": false,
|
|
"language": "python",
|
|
"ast_pattern": {
|
|
"type": "With",
|
|
"items": {
|
|
"contains": {
|
|
"type": "Call",
|
|
"func": {
|
|
"attr": "begin|transaction|atomic"
|
|
}
|
|
}
|
|
},
|
|
"missing": "try-except-with-rollback"
|
|
},
|
|
"message": "DATA INTEGRITY: Database transaction without proper rollback handling. Based on FAIL-DB-002 where transaction failure corrupted data.",
|
|
"severity": "error",
|
|
"suggestion": "Add exception handling: with db.begin() as tx: try: ... except: tx.rollback(); raise"
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-005",
|
|
"failure_id": "FAIL-CONFIG-002",
|
|
"name": "Mutable default argument in function",
|
|
"description": "Detects Python functions with mutable default arguments (lists, dicts) which cause unexpected shared state. Common source of bugs.",
|
|
"enabled": false,
|
|
"language": "python",
|
|
"ast_pattern": {
|
|
"type": "FunctionDef",
|
|
"args": {
|
|
"defaults": {
|
|
"contains": {
|
|
"type": "List|Dict|Set"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"message": "BUG PATTERN: Mutable default argument detected. This causes shared state between function calls - a classic Python gotcha.",
|
|
"severity": "warning",
|
|
"suggestion": "Use None as default and initialize inside: def func(arg=None): if arg is None: arg = []"
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-006",
|
|
"failure_id": "FAIL-API-002",
|
|
"name": "React useEffect with missing dependency",
|
|
"description": "Detects useEffect hooks that reference variables not in dependency array. Based on FAIL-API-002 where stale closure caused stale data.",
|
|
"enabled": false,
|
|
"language": "javascript",
|
|
"ast_pattern": {
|
|
"type": "CallExpression",
|
|
"callee": {
|
|
"type": "Identifier",
|
|
"name": "useEffect"
|
|
},
|
|
"arguments": [
|
|
{
|
|
"type": "ArrowFunctionExpression|FunctionExpression"
|
|
},
|
|
{
|
|
"type": "ArrayExpression",
|
|
"references_outside_scope": true
|
|
}
|
|
]
|
|
},
|
|
"message": "STALE CLOSURE: useEffect references variable not in dependency array. Based on FAIL-API-002 where this caused stale data bugs.",
|
|
"severity": "warning",
|
|
"suggestion": "Add missing dependencies to array or use eslint-plugin-react-hooks to catch automatically"
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-007",
|
|
"failure_id": "FAIL-ERR-001",
|
|
"name": "Bare except clause catching all exceptions",
|
|
"description": "Detects bare 'except:' clauses in Python that catch KeyboardInterrupt and SystemExit. Based on FAIL-ERR-001 where this masked critical errors.",
|
|
"enabled": false,
|
|
"language": "python",
|
|
"ast_pattern": {
|
|
"type": "Try",
|
|
"handlers": {
|
|
"contains": {
|
|
"type": "ExceptHandler",
|
|
"type": null
|
|
}
|
|
}
|
|
},
|
|
"message": "ERROR HANDLING: Bare except clause catches KeyboardInterrupt and SystemExit. Based on FAIL-ERR-001 where this prevented proper shutdown.",
|
|
"severity": "error",
|
|
"suggestion": "Be specific: except Exception: or except SpecificError:. Never use bare except: unless re-raising."
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-008",
|
|
"failure_id": "FAIL-SEC-001",
|
|
"name": "Insecure random for security purposes",
|
|
"description": "Detects use of Math.random() or random.random() for security-sensitive operations like tokens or passwords.",
|
|
"enabled": false,
|
|
"language": "any",
|
|
"ast_pattern": {
|
|
"type": "CallExpression|Call",
|
|
"callee": {
|
|
"name": "Math.random|random.random"
|
|
},
|
|
"context": "security|token|password|key|secret|auth|crypto"
|
|
},
|
|
"message": "SECURITY: Insecure random number generator used for security purpose. Use crypto-secure random instead.",
|
|
"severity": "critical",
|
|
"suggestion": "Use crypto.randomBytes() in Node.js, secrets module in Python, or SecureRandom in Java"
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-009",
|
|
"failure_id": "FAIL-TYPE-001",
|
|
"name": "Type assertion without validation",
|
|
"description": "Detects TypeScript type assertions (as Type) that bypass runtime checks. Based on FAIL-TYPE-001 where this caused runtime crashes.",
|
|
"enabled": false,
|
|
"language": "typescript",
|
|
"ast_pattern": {
|
|
"type": "TSAsExpression|TSTypeAssertion",
|
|
"target": "external_data|api_response|user_input|request_body",
|
|
"without": "validation|guard|check|parse"
|
|
},
|
|
"message": "TYPE SAFETY: Type assertion on untrusted data without validation. Based on FAIL-TYPE-001 where this caused production crash.",
|
|
"severity": "error",
|
|
"suggestion": "Use runtime validation: const data = schema.parse(apiResponse) instead of apiResponse as MyType"
|
|
},
|
|
{
|
|
"rule_id": "SEMANTIC-EX-010",
|
|
"failure_id": "FAIL-PERF-001",
|
|
"name": "N+1 database query pattern",
|
|
"description": "Detects loops that make database queries inside them. Based on FAIL-PERF-001 performance degradation.",
|
|
"enabled": false,
|
|
"language": "any",
|
|
"ast_pattern": {
|
|
"type": "For|ForIn|ForOf|While",
|
|
"body": {
|
|
"contains": {
|
|
"type": "CallExpression|Call|Await",
|
|
"callee": {
|
|
"attr": "get|fetch|find|query|select|filter"
|
|
},
|
|
"target": "database|db|model|orm"
|
|
}
|
|
}
|
|
},
|
|
"message": "PERFORMANCE: Database query inside loop (N+1 problem). Based on FAIL-PERF-001 where this caused severe performance degradation.",
|
|
"severity": "warning",
|
|
"suggestion": "Use eager loading: Model.objects.select_related() or fetch all data first, then process in memory"
|
|
}
|
|
],
|
|
"_comment": "SEMANTIC RULES are more powerful than pattern rules because they analyze AST structure. Use when: 1) Pattern rules produce too many false positives, 2) Need to check code context, 3) Detecting complex patterns. To enable: Copy rule, update IDs, set enabled: true, add to semantic-rules.json"
|
|
}
|