#!/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())