NAC_Blockchain/memory/tools/nac_lint.py

341 lines
12 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
NAC Lint Checker - 编译辅助检查器
自动检测违反NAC原则的代码
"""
import json
import re
import sys
from pathlib import Path
from typing import List, Dict, Any, Tuple
from dataclasses import dataclass
from enum import Enum
# 记忆系统根目录
MEMORY_ROOT = Path(__file__).parent.parent
class Severity(Enum):
"""违规严重性"""
CRITICAL = "critical"
HIGH = "high"
MEDIUM = "medium"
LOW = "low"
@dataclass
class Violation:
"""违规记录"""
rule_id: str
severity: Severity
file: str
line: int
column: int
message: str
found: str
suggestion: str
reference: str
class RuleEngine:
"""规则检查引擎"""
def __init__(self):
self.rules = []
self.load_rules()
def load_rules(self):
"""从记忆系统加载规则"""
# 加载术语映射规则
terminology_file = MEMORY_ROOT / "principles" / "terminology.json"
if terminology_file.exists():
with open(terminology_file, 'r', encoding='utf-8') as f:
terminology = json.load(f)
for mapping in terminology.get('mappings', []):
self.rules.append(self._create_terminology_rule(mapping))
# 加载架构原则规则
architecture_file = MEMORY_ROOT / "principles" / "architecture.json"
if architecture_file.exists():
with open(architecture_file, 'r', encoding='utf-8') as f:
architecture = json.load(f)
for principle in architecture.get('principles', []):
if principle.get('principle_id') == 'ARCH_002':
# OpCode命名规范
self.rules.append(self._create_opcode_naming_rule(principle))
elif principle.get('principle_id') == 'ARCH_003':
# Blake3哈希规范
self.rules.append(self._create_blake3_rule(principle))
elif principle.get('principle_id') == 'ARCH_004':
# 代码保留原则
self.rules.append(self._create_no_delete_rule(principle))
def _create_terminology_rule(self, mapping: Dict[str, Any]) -> Dict[str, Any]:
"""创建术语检查规则"""
wrong_term = mapping['wrong_term']
correct_term = mapping['correct_term']
# 构建正则表达式
# 支持多个错误术语(用/分隔)
terms = wrong_term.split('/')
pattern_parts = []
for term in terms:
# 匹配整个单词,不区分大小写
pattern_parts.append(rf'\b{re.escape(term.strip())}\b')
pattern = '|'.join(pattern_parts)
return {
'rule_id': mapping['mapping_id'],
'category': 'terminology',
'severity': Severity.CRITICAL,
'title': f"禁止使用{wrong_term}术语",
'description': mapping['explanation'],
'pattern': pattern,
'flags': re.IGNORECASE,
'suggestion': correct_term,
'reference': f"memory/principles/terminology.json#{mapping['mapping_id']}",
'must_not_use': mapping.get('must_not_use', [])
}
def _create_opcode_naming_rule(self, principle: Dict[str, Any]) -> Dict[str, Any]:
"""创建OpCode命名规范规则"""
return {
'rule_id': 'ARCH_002',
'category': 'naming',
'severity': Severity.HIGH,
'title': 'OpCode命名必须使用UPPER_CASE',
'description': principle['description'],
'pattern': r'enum\s+OpCode\s*\{[^}]*\b([A-Z][a-z]+[A-Z][a-zA-Z]*)\b',
'flags': 0,
'suggestion': '使用UPPER_CASE命名如PUSH1, CR_CREATE',
'reference': 'memory/principles/architecture.json#ARCH_002'
}
def _create_blake3_rule(self, principle: Dict[str, Any]) -> Dict[str, Any]:
"""创建Blake3哈希规范规则"""
return {
'rule_id': 'ARCH_003',
'category': 'cryptography',
'severity': Severity.HIGH,
'title': '必须使用Blake3哈希算法',
'description': principle['description'],
'pattern': r'\b(sha256|SHA256|keccak256|Keccak256|sha3|SHA3|md5|MD5)\b',
'flags': 0,
'suggestion': '使用Blake3哈希算法',
'reference': 'memory/principles/architecture.json#ARCH_003'
}
def _create_no_delete_rule(self, principle: Dict[str, Any]) -> Dict[str, Any]:
"""创建代码保留原则规则"""
return {
'rule_id': 'ARCH_004',
'category': 'architecture',
'severity': Severity.HIGH,
'title': '禁止使用#[allow(unused)]',
'description': principle['description'],
'pattern': r'#\[allow\(unused\)\]',
'flags': 0,
'suggestion': '添加proper imports而非隐藏警告',
'reference': 'memory/principles/architecture.json#ARCH_004'
}
class CodeScanner:
"""代码扫描器"""
def __init__(self, rule_engine: RuleEngine):
self.rule_engine = rule_engine
self.violations = []
def scan_file(self, file_path: Path) -> List[Violation]:
"""扫描单个文件"""
violations = []
try:
with open(file_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
for line_num, line in enumerate(lines, 1):
for rule in self.rule_engine.rules:
matches = re.finditer(rule['pattern'], line, rule.get('flags', 0))
for match in matches:
violation = Violation(
rule_id=rule['rule_id'],
severity=rule['severity'],
file=str(file_path),
line=line_num,
column=match.start() + 1,
message=rule['title'],
found=match.group(0),
suggestion=rule['suggestion'],
reference=rule['reference']
)
violations.append(violation)
except Exception as e:
print(f"Error scanning {file_path}: {e}", file=sys.stderr)
return violations
def scan_directory(self, directory: Path, extensions: List[str] = None) -> List[Violation]:
"""扫描目录"""
if extensions is None:
extensions = ['.rs', '.toml', '.json', '.md']
violations = []
for ext in extensions:
for file_path in directory.rglob(f'*{ext}'):
# 跳过target和node_modules目录
if 'target' in file_path.parts or 'node_modules' in file_path.parts:
continue
file_violations = self.scan_file(file_path)
violations.extend(file_violations)
return violations
class ViolationReporter:
"""违规报告器"""
@staticmethod
def report_console(violations: List[Violation], verbose: bool = True):
"""控制台输出"""
if not violations:
print("✅ No violations found. Code is compliant with NAC principles.")
return
# 按严重性分组
by_severity = {
Severity.CRITICAL: [],
Severity.HIGH: [],
Severity.MEDIUM: [],
Severity.LOW: []
}
for violation in violations:
by_severity[violation.severity].append(violation)
print("\nNAC Lint Checker v1.0.0")
print("=" * 80)
# 输出违规
for severity in [Severity.CRITICAL, Severity.HIGH, Severity.MEDIUM, Severity.LOW]:
items = by_severity[severity]
if not items:
continue
icon = "" if severity == Severity.CRITICAL else "⚠️ "
print(f"\n{icon} {severity.value.upper()}: {len(items)} violation(s)")
print("-" * 80)
for violation in items:
print(f"\n{violation.message} [{violation.rule_id}]")
print(f" File: {violation.file}:{violation.line}:{violation.column}")
print(f" Found: {violation.found}")
print(f" Should be: {violation.suggestion}")
if verbose:
print(f" Reference: {violation.reference}")
# 摘要
print("\n" + "=" * 80)
print("Summary:")
print(f"{len(by_severity[Severity.CRITICAL])} critical violations")
print(f" ⚠️ {len(by_severity[Severity.HIGH])} high violations")
print(f" {len(by_severity[Severity.MEDIUM])} medium violations")
print(f" 💡 {len(by_severity[Severity.LOW])} low violations")
if by_severity[Severity.CRITICAL]:
print("\n❌ Build blocked due to critical violations.")
return 1
else:
print("\n⚠️ Build allowed with warnings.")
return 0
@staticmethod
def report_json(violations: List[Violation], output_file: Path = None):
"""JSON输出"""
from datetime import datetime
report = {
'version': '1.0.0',
'timestamp': datetime.now().isoformat(),
'summary': {
'total_violations': len(violations),
'by_severity': {
'critical': len([v for v in violations if v.severity == Severity.CRITICAL]),
'high': len([v for v in violations if v.severity == Severity.HIGH]),
'medium': len([v for v in violations if v.severity == Severity.MEDIUM]),
'low': len([v for v in violations if v.severity == Severity.LOW])
}
},
'violations': [
{
'rule_id': v.rule_id,
'severity': v.severity.value,
'file': v.file,
'line': v.line,
'column': v.column,
'message': v.message,
'found': v.found,
'suggestion': v.suggestion,
'reference': v.reference
}
for v in violations
]
}
if output_file:
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print(f"✅ Report saved to {output_file}")
else:
print(json.dumps(report, ensure_ascii=False, indent=2))
def main():
"""主函数"""
import argparse
parser = argparse.ArgumentParser(description='NAC Lint Checker - 编译辅助检查器')
parser.add_argument('command', choices=['check', 'list-rules'], help='命令')
parser.add_argument('--path', '-p', default='.', help='扫描路径(默认当前目录)')
parser.add_argument('--output', '-o', choices=['console', 'json'], default='console', help='输出格式')
parser.add_argument('--output-file', help='JSON输出文件路径')
parser.add_argument('--verbose', '-v', action='store_true', help='详细输出')
parser.add_argument('--all', '-a', action='store_true', help='扫描所有文件包括target')
args = parser.parse_args()
# 初始化规则引擎
rule_engine = RuleEngine()
if args.command == 'list-rules':
print(f"\nNAC Lint Checker - Loaded {len(rule_engine.rules)} rules:")
print("=" * 80)
for rule in rule_engine.rules:
print(f"\n[{rule['rule_id']}] {rule['title']}")
print(f" Category: {rule['category']}")
print(f" Severity: {rule['severity'].value}")
print(f" Description: {rule['description']}")
return 0
# 扫描代码
scanner = CodeScanner(rule_engine)
scan_path = Path(args.path).resolve()
print(f"Scanning: {scan_path}")
if scan_path.is_file():
violations = scanner.scan_file(scan_path)
else:
violations = scanner.scan_directory(scan_path)
# 输出报告
if args.output == 'json':
output_file = Path(args.output_file) if args.output_file else None
ViolationReporter.report_json(violations, output_file)
return 0
else:
return ViolationReporter.report_console(violations, args.verbose)
if __name__ == "__main__":
sys.exit(main())