137 @param repeat flag indicating to report each occurrence of a code |
139 @param repeat flag indicating to report each occurrence of a code |
138 @type bool |
140 @type bool |
139 @param args dictionary of arguments for the security checks |
141 @param args dictionary of arguments for the security checks |
140 @type dict |
142 @type dict |
141 """ |
143 """ |
142 self.__select = tuple(select) |
144 super().__init__( |
143 self.__ignore = tuple(ignore) |
145 SecurityChecker.Category, |
144 self.__expected = expected[:] |
146 source, |
145 self.__repeat = repeat |
147 filename, |
146 self.__filename = filename |
148 tree, |
147 self.__source = source[:] |
149 select, |
148 self.__tree = copy.deepcopy(tree) |
150 ignore, |
149 self.__args = args |
151 expected, |
150 |
152 repeat, |
151 # statistics counters |
153 args, |
152 self.counters = {} |
154 ) |
153 |
|
154 # collection of detected errors |
|
155 self.errors = [] |
|
156 |
155 |
157 checkersWithCodes = Checks.generateCheckersDict() |
156 checkersWithCodes = Checks.generateCheckersDict() |
158 |
157 |
159 self.__checkers = collections.defaultdict(list) |
158 self.__checkers = collections.defaultdict(list) |
160 for checkType, checkersList in checkersWithCodes.items(): |
159 for checkType, checkersList in checkersWithCodes.items(): |
161 for checker, codes in checkersList: |
160 for checker, codes in checkersList: |
162 if any(not (code and self.__ignoreCode(code)) for code in codes): |
161 if any( |
|
162 not (msgCode and self._ignoreCode(msgCode)) for msgCode in codes |
|
163 ): |
163 self.__checkers[checkType].append(checker) |
164 self.__checkers[checkType].append(checker) |
164 |
165 |
165 def __ignoreCode(self, code): |
166 def addError(self, lineNumber, offset, msgCode, severity, confidence, *args): |
166 """ |
|
167 Private method to check if the message code should be ignored. |
|
168 |
|
169 @param code message code to check for |
|
170 @type str |
|
171 @return flag indicating to ignore the given code |
|
172 @rtype bool |
|
173 """ |
|
174 return code in self.__ignore or ( |
|
175 code.startswith(self.__ignore) and not code.startswith(self.__select) |
|
176 ) |
|
177 |
|
178 def reportError(self, lineNumber, offset, code, severity, confidence, *args): |
|
179 """ |
167 """ |
180 Public method to record an issue. |
168 Public method to record an issue. |
181 |
169 |
182 @param lineNumber line number of the issue |
170 @param lineNumber line number of the issue |
183 @type int |
171 @type int |
184 @param offset position within line of the issue |
172 @param offset position within line of the issue |
185 @type int |
173 @type int |
186 @param code message code |
174 @param msgCode message code |
187 @type str |
175 @type str |
188 @param severity severity code (H = high, M = medium, L = low, |
176 @param severity severity code (H = high, M = medium, L = low, |
189 U = undefined) |
177 U = undefined) |
190 @type str |
178 @type str |
191 @param confidence confidence code (H = high, M = medium, L = low, |
179 @param confidence confidence code (H = high, M = medium, L = low, |
192 U = undefined) |
180 U = undefined) |
193 @type str |
181 @type str |
194 @param args arguments for the message |
182 @param args arguments for the message |
195 @type list |
183 @type list |
196 """ |
184 """ |
197 if self.__ignoreCode(code): |
185 if self._ignoreCode(msgCode): |
198 return |
186 return |
199 |
187 |
200 if code in self.counters: |
188 if msgCode in self.counters: |
201 self.counters[code] += 1 |
189 self.counters[msgCode] += 1 |
202 else: |
190 else: |
203 self.counters[code] = 1 |
191 self.counters[msgCode] = 1 |
204 |
192 |
205 # Don't care about expected codes |
193 # Don't care about expected codes |
206 if code in self.__expected: |
194 if msgCode in self.expected: |
207 return |
195 return |
208 |
196 |
209 if code and (self.counters[code] == 1 or self.__repeat): |
197 if msgCode and (self.counters[msgCode] == 1 or self.repeat): |
210 # record the issue with one based line number |
198 # record the issue with one based line number |
211 self.errors.append( |
199 self.errors.append( |
212 { |
200 { |
213 "file": self.__filename, |
201 "file": self.filename, |
214 "line": lineNumber + 1, |
202 "line": lineNumber + 1, |
215 "offset": offset, |
203 "offset": offset, |
216 "code": code, |
204 "code": msgCode, |
217 "args": args, |
205 "args": args, |
218 "severity": severity, |
206 "severity": severity, |
219 "confidence": confidence, |
207 "confidence": confidence, |
220 } |
208 } |
221 ) |
209 ) |
225 Public method to get the configuration dictionary. |
213 Public method to get the configuration dictionary. |
226 |
214 |
227 @return dictionary containing the configuration |
215 @return dictionary containing the configuration |
228 @rtype dict |
216 @rtype dict |
229 """ |
217 """ |
230 return self.__args |
218 return self.args |
231 |
219 |
232 def run(self): |
220 def run(self): |
233 """ |
221 """ |
234 Public method to check the given source against security related |
222 Public method to check the given source against security related |
235 conditions. |
223 conditions. |
236 """ |
224 """ |
237 if not self.__filename: |
225 if not self.filename: |
238 # don't do anything, if essential data is missing |
226 # don't do anything, if essential data is missing |
239 return |
227 return |
240 |
228 |
241 if not self.__checkers: |
229 if not self.__checkers: |
242 # don't do anything, if no codes were selected |
230 # don't do anything, if no codes were selected |
243 return |
231 return |
244 |
232 |
245 securityNodeVisitor = SecurityNodeVisitor( |
233 securityNodeVisitor = SecurityNodeVisitor( |
246 self, self.__checkers, self.__filename, self.__source |
234 self, self.__checkers, self.filename, self.source |
247 ) |
235 ) |
248 securityNodeVisitor.generic_visit(self.__tree) |
236 securityNodeVisitor.generic_visit(self.tree) |
249 securityNodeVisitor.checkFile() |
237 securityNodeVisitor.checkFile() |