1/* 2 * Copyright (c) 2024 - 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { ArkFile } from 'arkanalyzer'; 17import { CheckEntry } from './CheckEntry'; 18import { ConfigUtils } from './ConfigUtils'; 19import { CheckerUtils } from '../checker/CheckerUtils'; 20import { file2CheckRuleMap, project2CheckRuleMap } from './CheckerIndex'; 21import { Rule } from '../../model/Rule'; 22import { RuleConfig } from '../../model/RuleConfig'; 23import { fileCheckBuilder, projectCheckBuilder } from './CheckBuilder'; 24import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; 25import { FileUtils } from './FileUtils'; 26 27const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'fileRuleMapping'); 28 29export async function fileRuleMapping(checkFileList: string[], checkEntry: CheckEntry): Promise<boolean> { 30 // 获取规则配置文件的规则,除了override 31 const allRulesMap = ConfigUtils.getRuleMap(checkEntry.ruleConfig, checkEntry.projectConfig, checkEntry.message); 32 if (allRulesMap.size === 0) { 33 checkEntry.message?.progressNotify(1, 'No rule to check'); 34 return false; 35 } 36 37 let arkFiles: ArkFile[] = []; 38 const fiRulesMap: Map<string, Rule> = new Map(); 39 const fileRulesMap = await createFileRulesMap(checkFileList, allRulesMap, checkEntry, file2CheckRuleMap, fiRulesMap); 40 for (const filePath of checkFileList) { 41 try { 42 const arkFile = CheckerUtils.getArkFileByFilePath(checkEntry.scene, filePath); 43 if (!arkFile) { 44 continue; 45 } 46 47 arkFiles.push(arkFile); 48 const enabledRules = fileRulesMap.get(filePath); 49 if (enabledRules) { 50 checkEntry.addFileCheck(fileCheckBuilder(arkFile, enabledRules)); 51 } 52 } catch (error) { 53 logger.error(`Error processing file ${filePath}: ${(error as Error).message}`); 54 } 55 } 56 57 const proRulesMap: Map<string, Rule> = new Map(); 58 const projectRulesMap = await createFileRulesMap(checkFileList, allRulesMap, checkEntry, project2CheckRuleMap, proRulesMap); 59 const projectRules = Array.from(proRulesMap.values()); 60 try { 61 checkEntry.addProjectCheck(projectCheckBuilder(arkFiles, projectRules)); 62 checkEntry.projectCheck.ruleMap = projectRulesMap; 63 } catch (error) { 64 logger.error(`Error adding project check: ${(error as Error).message}`); 65 } 66 return true; 67} 68 69function filterRule(allRulesMap: Map<string, Rule>, filterMap?: Map<string, Rule[]>): Rule[] { 70 const rules: Rule[] = []; 71 for (const [key, value] of allRulesMap) { 72 if (filterMap && !filterMap.has(key)) { 73 continue; 74 } 75 rules.push(value); 76 } 77 return rules; 78} 79 80async function createFileRulesMap(allFiles: string[], allRulesMap: Map<string, Rule>, checkEntry: CheckEntry, 81 checksRuleMap: Map<string, any>, proRulesMap: Map<string, Rule>): Promise<Map<string, Rule[]>> { 82 // 获取配置的规则列表 83 let fileRulesMap: Map<string, Rule[]> = new Map(); 84 const ruleMap = filterRule(allRulesMap, checksRuleMap); 85 86 const defaultRules = Array.from(ruleMap.values()); 87 allFiles.forEach(filePath => fileRulesMap.set(filePath, defaultRules)); 88 ruleMap.forEach(rule => { 89 proRulesMap.set(rule.ruleId, rule); 90 }); 91 // 检查额外规则覆盖 92 for (const override of checkEntry.ruleConfig.overrides ?? []) { 93 try { 94 const overrideFileRulesMap = await createFileRulesMapWithOverride(checkEntry, override, checksRuleMap, proRulesMap); 95 fileRulesMap = mergeFileRulesMap(fileRulesMap, overrideFileRulesMap); 96 } catch (error) { 97 logger.error(`Error check extra rule overrides: ${(error as Error).message}`); 98 } 99 } 100 return fileRulesMap; 101} 102 103async function createFileRulesMapWithOverride(checkEntry: CheckEntry, override: RuleConfig, 104 checksRuleMap: Map<string, any>, proRulesMap: Map<string, Rule>): Promise<Map<string, Rule[]>> { 105 let checkFileList = checkEntry.selectFileList.map(file => file.filePath); 106 if (checkFileList.length === 0) { 107 checkFileList = FileUtils.getAllFiles(checkEntry.projectConfig.projectPath, ['.ts', '.ets', '.json5']); 108 } 109 checkFileList = await FileUtils.getFiltedFiles(checkFileList, override); 110 const allRuleMap = ConfigUtils.getRuleMap(override, checkEntry.projectConfig, checkEntry.message); 111 const ruleMap = filterRule(allRuleMap, checksRuleMap); 112 ruleMap.forEach(rule => { 113 if (!proRulesMap.has(rule.ruleId)) { 114 proRulesMap.set(rule.ruleId, rule); 115 } 116 }); 117 const fileRulesMap: Map<string, Rule[]> = new Map(); 118 const defaultRules = Array.from(ruleMap.values()); 119 checkFileList.forEach(filePath => fileRulesMap.set(filePath, defaultRules)); 120 return fileRulesMap; 121} 122 123function mergeFileRulesMap(fileRulesMap: Map<string, Rule[]>, 124 overrideFileRulesMap: Map<string, Rule[]>): Map<string, Rule[]> { 125 // 取fileRule和overrideRule交集 126 for (const [key, vals] of overrideFileRulesMap) { 127 if (!fileRulesMap.has(key) || vals.length === 0) { 128 continue; 129 } 130 let fileRules = fileRulesMap.get(key); 131 if (!fileRules || fileRules.length === 0) { 132 fileRulesMap.set(key, vals); 133 continue; 134 } 135 let newRules = [...fileRules]; 136 vals.forEach(val => { 137 let existIndex = fileRules?.findIndex(fileRule => fileRule.ruleId === val.ruleId); 138 if (existIndex === undefined || existIndex === -1) { 139 newRules.push(val); 140 } else { 141 newRules[existIndex] = val; 142 } 143 }); 144 fileRulesMap.set(key, newRules); 145 } 146 // 筛除关闭的rule 147 const filteredRulesMap = new Map<string, Rule[]>(); 148 for (const [key, rules] of fileRulesMap) { 149 const filteredRules = rules.filter(rule => rule.alert !== 0); 150 filteredRulesMap.set(key, filteredRules); 151 } 152 return filteredRulesMap; 153}