Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1231)

Side by Side Diff: PRESUBMIT.py

Issue 2070483002: Add PRESUBMIT rule to make sure IPC changes are security reviewed. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address review comments Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/common/OWNERS » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Top-level presubmit script for Chromium. 5 """Top-level presubmit script for Chromium.
6 6
7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts 7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8 for more details about the presubmit API built into depot_tools. 8 for more details about the presubmit API built into depot_tools.
9 """ 9 """
10 10
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 def _CheckDCHECK_IS_ONHasBraces(input_api, output_api): 421 def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
422 """Checks to make sure DCHECK_IS_ON() does not skip the braces.""" 422 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
423 errors = [] 423 errors = []
424 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))', 424 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
425 input_api.re.MULTILINE) 425 input_api.re.MULTILINE)
426 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile): 426 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
427 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))): 427 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
428 continue 428 continue
429 for lnum, line in f.ChangedContents(): 429 for lnum, line in f.ChangedContents():
430 if input_api.re.search(pattern, line): 430 if input_api.re.search(pattern, line):
431 errors.append(output_api.PresubmitError( 431 errors.append(output_api.PresubmitError(
432 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' + 432 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
433 'DCHECK_IS_ON()", not forgetting the braces.') 433 'DCHECK_IS_ON()", not forgetting the braces.')
434 % (f.LocalPath(), lnum))) 434 % (f.LocalPath(), lnum)))
435 return errors 435 return errors
436 436
437 437
438 def _FindHistogramNameInLine(histogram_name, line): 438 def _FindHistogramNameInLine(histogram_name, line):
439 """Tries to find a histogram name or prefix in a line.""" 439 """Tries to find a histogram name or prefix in a line."""
440 if not "affected-histogram" in line: 440 if not "affected-histogram" in line:
441 return histogram_name in line 441 return histogram_name in line
442 # A histogram_suffixes tag type has an affected-histogram name as a prefix of 442 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
443 # the histogram_name. 443 # the histogram_name.
444 if not '"' in line: 444 if not '"' in line:
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 return True 583 return True
584 return False 584 return False
585 585
586 def CheckForMatch(affected_file, line_num, line, func_name, message, error): 586 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
587 matched = False 587 matched = False
588 if func_name[0:1] == '/': 588 if func_name[0:1] == '/':
589 regex = func_name[1:] 589 regex = func_name[1:]
590 if input_api.re.search(regex, line): 590 if input_api.re.search(regex, line):
591 matched = True 591 matched = True
592 elif func_name in line: 592 elif func_name in line:
593 matched = True 593 matched = True
594 if matched: 594 if matched:
595 problems = warnings; 595 problems = warnings
596 if error: 596 if error:
597 problems = errors; 597 problems = errors
598 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num)) 598 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
599 for message_line in message: 599 for message_line in message:
600 problems.append(' %s' % message_line) 600 problems.append(' %s' % message_line)
601 601
602 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h')) 602 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
603 for f in input_api.AffectedFiles(file_filter=file_filter): 603 for f in input_api.AffectedFiles(file_filter=file_filter):
604 for line_num, line in f.ChangedContents(): 604 for line_num, line in f.ChangedContents():
605 for func_name, message, error in _BANNED_OBJC_FUNCTIONS: 605 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
606 CheckForMatch(f, line_num, line, func_name, message, error) 606 CheckForMatch(f, line_num, line, func_name, message, error)
607 607
(...skipping 784 matching lines...) Expand 10 before | Expand all | Expand 10 after
1392 import checkstyle 1392 import checkstyle
1393 finally: 1393 finally:
1394 # Restore sys.path to what it was before. 1394 # Restore sys.path to what it was before.
1395 sys.path = original_sys_path 1395 sys.path = original_sys_path
1396 1396
1397 return checkstyle.RunCheckstyle( 1397 return checkstyle.RunCheckstyle(
1398 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml', 1398 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
1399 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST) 1399 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
1400 1400
1401 1401
1402 def _CheckIpcOwners(input_api, output_api):
1403 """Checks that affected files involving IPC have an IPC OWNERS rule.
1404
1405 Whether or not a file affects IPC is determined by a simple whitelist of
1406 filename patterns."""
1407 file_patterns = [
1408 '*_messages.cc',
1409 '*_messages*.h',
1410 '*_param_traits*.*',
1411 '*.mojom',
1412 '*_struct_traits*.*',
1413 '*_type_converters*.*',
1414 ]
1415
1416 # Dictionary mapping an OWNERS file path to Patterns.
1417 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1418 # rules ) to a PatternEntry.
1419 # PatternEntry is a dictionary with two keys:
1420 # - 'files': the files that are matched by this pattern
1421 # - 'rules': the per-file rules needed for this pattern
1422 # For example, if we expect OWNERS file to contain rules for *.mojom and
1423 # *_struct_traits*.*, Patterns might look like this:
1424 # {
1425 # '*.mojom': {
1426 # 'files': ...,
1427 # 'rules': [
1428 # 'per-file *.mojom=set noparent',
1429 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1430 # ],
1431 # },
1432 # '*_struct_traits*.*': {
1433 # 'files': ...,
1434 # 'rules': [
1435 # 'per-file *_struct_traits*.*=set noparent',
1436 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1437 # ],
1438 # },
1439 # }
1440 to_check = {}
1441
1442 # Iterate through the affected files to see what we actually need to check
1443 # for. We should only nag patch authors about per-file rules if a file in that
1444 # directory would match that pattern. If a directory only contains *.mojom
1445 # files and no *_messages*.h files, we should only nag about rules for
1446 # *.mojom files.
1447 for f in input_api.change.AffectedFiles():
1448 for pattern in file_patterns:
1449 if input_api.fnmatch.fnmatch(
1450 input_api.os_path.basename(f.LocalPath()), pattern):
1451 owners_file = input_api.os_path.join(
1452 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1453 if owners_file not in to_check:
1454 to_check[owners_file] = {}
1455 if pattern not in to_check[owners_file]:
1456 to_check[owners_file][pattern] = {
1457 'files': [],
1458 'rules': [
1459 'per-file %s=set noparent' % pattern,
1460 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1461 ]
1462 }
1463 to_check[owners_file][pattern]['files'].append(f)
1464 break
1465
1466 # Now go through the OWNERS files we collected, filtering out rules that are
1467 # already present in that OWNERS file.
1468 for owners_file, patterns in to_check.iteritems():
1469 try:
1470 with file(owners_file) as f:
1471 for line in f.read().splitlines():
1472 for entry in patterns.itervalues():
1473 entry['rules'] = [rule for rule in entry['rules'] if rule != line]
Dirk Pranke 2016/06/18 20:49:26 Maybe lines = f.read().splitlines() for entry
dcheng 2016/06/19 00:03:28 I tweaked this slightly and put the lines in a set
1474 except IOError:
1475 # No OWNERS file, so all the rules are definitely missing.
1476 continue
1477
1478 # All the remaining lines weren't found in OWNERS files, so emit an error.
1479 errors = []
1480 for owners_file, patterns in to_check.iteritems():
1481 missing_lines = []
1482 files = []
1483 for pattern, entry in patterns.iteritems():
1484 missing_lines.extend(entry['rules'])
1485 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1486 if missing_lines:
1487 errors.append(
1488 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1489 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1490
1491 results = []
1492 if errors:
1493 results.append(output_api.PresubmitError(
1494 'Found changes to IPC files without a security OWNER!',
1495 long_text='\n\n'.join(errors)))
1496
1497 return results
1498
1499
1402 def _CheckAndroidToastUsage(input_api, output_api): 1500 def _CheckAndroidToastUsage(input_api, output_api):
1403 """Checks that code uses org.chromium.ui.widget.Toast instead of 1501 """Checks that code uses org.chromium.ui.widget.Toast instead of
1404 android.widget.Toast (Chromium Toast doesn't force hardware 1502 android.widget.Toast (Chromium Toast doesn't force hardware
1405 acceleration on low-end devices, saving memory). 1503 acceleration on low-end devices, saving memory).
1406 """ 1504 """
1407 toast_import_pattern = input_api.re.compile( 1505 toast_import_pattern = input_api.re.compile(
1408 r'^import android\.widget\.Toast;$') 1506 r'^import android\.widget\.Toast;$')
1409 1507
1410 errors = [] 1508 errors = []
1411 1509
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after
1855 results.extend(_CheckNoDeprecatedCSS(input_api, output_api)) 1953 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
1856 results.extend(_CheckNoDeprecatedJS(input_api, output_api)) 1954 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
1857 results.extend(_CheckParseErrors(input_api, output_api)) 1955 results.extend(_CheckParseErrors(input_api, output_api))
1858 results.extend(_CheckForIPCRules(input_api, output_api)) 1956 results.extend(_CheckForIPCRules(input_api, output_api))
1859 results.extend(_CheckForCopyrightedCode(input_api, output_api)) 1957 results.extend(_CheckForCopyrightedCode(input_api, output_api))
1860 results.extend(_CheckForWindowsLineEndings(input_api, output_api)) 1958 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
1861 results.extend(_CheckSingletonInHeaders(input_api, output_api)) 1959 results.extend(_CheckSingletonInHeaders(input_api, output_api))
1862 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api)) 1960 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
1863 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api)) 1961 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
1864 results.extend(_CheckJavaStyle(input_api, output_api)) 1962 results.extend(_CheckJavaStyle(input_api, output_api))
1963 results.extend(_CheckIpcOwners(input_api, output_api))
1865 1964
1866 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()): 1965 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1867 results.extend(input_api.canned_checks.RunUnitTestsInDirectory( 1966 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1868 input_api, output_api, 1967 input_api, output_api,
1869 input_api.PresubmitLocalPath(), 1968 input_api.PresubmitLocalPath(),
1870 whitelist=[r'^PRESUBMIT_test\.py$'])) 1969 whitelist=[r'^PRESUBMIT_test\.py$']))
1871 return results 1970 return results
1872 1971
1873 1972
1874 def _CheckAuthorizedAuthor(input_api, output_api): 1973 def _CheckAuthorizedAuthor(input_api, output_api):
1875 """For non-googler/chromites committers, verify the author's email address is 1974 """For non-googler/chromites committers, verify the author's email address is
1876 in AUTHORS. 1975 in AUTHORS.
1877 """ 1976 """
1878 # TODO(maruel): Add it to input_api?
1879 import fnmatch
1880
1881 author = input_api.change.author_email 1977 author = input_api.change.author_email
1882 if not author: 1978 if not author:
1883 input_api.logging.info('No author, skipping AUTHOR check') 1979 input_api.logging.info('No author, skipping AUTHOR check')
1884 return [] 1980 return []
1885 authors_path = input_api.os_path.join( 1981 authors_path = input_api.os_path.join(
1886 input_api.PresubmitLocalPath(), 'AUTHORS') 1982 input_api.PresubmitLocalPath(), 'AUTHORS')
1887 valid_authors = ( 1983 valid_authors = (
1888 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line) 1984 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1889 for line in open(authors_path)) 1985 for line in open(authors_path))
1890 valid_authors = [item.group(1).lower() for item in valid_authors if item] 1986 valid_authors = [item.group(1).lower() for item in valid_authors if item]
1891 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors): 1987 if not any(input_api.fnmatch.fnmatch(author.lower(), valid)
1988 for valid in valid_authors):
1892 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors)) 1989 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
1893 return [output_api.PresubmitPromptWarning( 1990 return [output_api.PresubmitPromptWarning(
1894 ('%s is not in AUTHORS file. If you are a new contributor, please visit' 1991 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1895 '\n' 1992 '\n'
1896 'http://www.chromium.org/developers/contributing-code and read the ' 1993 'http://www.chromium.org/developers/contributing-code and read the '
1897 '"Legal" section\n' 1994 '"Legal" section\n'
1898 'If you are a chromite, verify the contributor signed the CLA.') % 1995 'If you are a chromite, verify the contributor signed the CLA.') %
1899 author)] 1996 author)]
1900 return [] 1997 return []
1901 1998
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
2122 results.extend(input_api.canned_checks.CheckTreeIsOpen( 2219 results.extend(input_api.canned_checks.CheckTreeIsOpen(
2123 input_api, 2220 input_api,
2124 output_api, 2221 output_api,
2125 json_url='http://chromium-status.appspot.com/current?format=json')) 2222 json_url='http://chromium-status.appspot.com/current?format=json'))
2126 2223
2127 results.extend(input_api.canned_checks.CheckChangeHasBugField( 2224 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2128 input_api, output_api)) 2225 input_api, output_api))
2129 results.extend(input_api.canned_checks.CheckChangeHasDescription( 2226 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2130 input_api, output_api)) 2227 input_api, output_api))
2131 return results 2228 return results
OLDNEW
« no previous file with comments | « no previous file | content/common/OWNERS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698