test_patch.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # Checks related to the patch's CVE lines
  2. #
  3. # Copyright (C) 2016 Intel Corporation
  4. #
  5. # SPDX-License-Identifier: GPL-2.0-only
  6. #
  7. import base
  8. import os
  9. import patchtest_patterns
  10. import pyparsing
  11. class TestPatch(base.Base):
  12. @classmethod
  13. def setUpClassLocal(cls):
  14. cls.newpatches = []
  15. # get just those relevant patches: new software patches
  16. for patch in cls.patchset:
  17. if patch.path.endswith('.patch') and patch.is_added_file:
  18. cls.newpatches.append(patch)
  19. cls.mark = str(patchtest_patterns.signed_off_by_prefix).strip('"')
  20. # match PatchSignedOffBy.mark with '+' preceding it
  21. cls.prog = patchtest_patterns.patch_signed_off_by
  22. def setUp(self):
  23. if self.unidiff_parse_error:
  24. self.skip('Parse error %s' % self.unidiff_parse_error)
  25. self.valid_status = ", ".join(patchtest_patterns.upstream_status_nonliteral_valid_status)
  26. self.standard_format = "Upstream-Status: <Valid status>"
  27. # we are just interested in series that introduce CVE patches, thus discard other
  28. # possibilities: modification to current CVEs, patch directly introduced into the
  29. # recipe, upgrades already including the CVE, etc.
  30. new_cves = [p for p in self.patchset if p.path.endswith('.patch') and p.is_added_file]
  31. if not new_cves:
  32. self.skip('No new CVE patches introduced')
  33. def test_upstream_status_presence_format(self):
  34. if not TestPatch.newpatches:
  35. self.skip("There are no new software patches, no reason to test Upstream-Status presence/format")
  36. for newpatch in TestPatch.newpatches:
  37. payload = newpatch.__str__()
  38. if not patchtest_patterns.upstream_status_regex.search_string(payload):
  39. self.fail(
  40. "Added patch file is missing Upstream-Status: <Valid status> in the commit message",
  41. data=[
  42. ("Standard format", self.standard_format),
  43. ("Valid status", self.valid_status),
  44. ],
  45. )
  46. for line in payload.splitlines():
  47. if patchtest_patterns.patchmetadata_regex.match(line):
  48. continue
  49. if patchtest_patterns.upstream_status_regex.search_string(line):
  50. if patchtest_patterns.inappropriate.searchString(line):
  51. try:
  52. patchtest_patterns.upstream_status_inappropriate_info.parseString(
  53. line.lstrip("+")
  54. )
  55. except pyparsing.ParseException as pe:
  56. self.fail(
  57. "Upstream-Status is Inappropriate, but no reason was provided",
  58. data=[
  59. ("Current", pe.pstr),
  60. (
  61. "Standard format",
  62. "Upstream-Status: Inappropriate [reason]",
  63. ),
  64. ],
  65. )
  66. elif patchtest_patterns.submitted.searchString(line):
  67. try:
  68. patchtest_patterns.upstream_status_submitted_info.parseString(
  69. line.lstrip("+")
  70. )
  71. except pyparsing.ParseException as pe:
  72. self.fail(
  73. "Upstream-Status is Submitted, but it is not mentioned where",
  74. data=[
  75. ("Current", pe.pstr),
  76. (
  77. "Standard format",
  78. "Upstream-Status: Submitted [where]",
  79. ),
  80. ],
  81. )
  82. else:
  83. try:
  84. patchtest_patterns.upstream_status.parseString(line.lstrip("+"))
  85. except pyparsing.ParseException as pe:
  86. self.fail(
  87. "Upstream-Status is in incorrect format",
  88. data=[
  89. ("Current", pe.pstr),
  90. ("Standard format", self.standard_format),
  91. ("Valid status", self.valid_status),
  92. ],
  93. )
  94. def test_signed_off_by_presence(self):
  95. if not TestPatch.newpatches:
  96. self.skip("There are no new software patches, no reason to test %s presence" % PatchSignedOffBy.mark)
  97. for newpatch in TestPatch.newpatches:
  98. payload = newpatch.__str__()
  99. for line in payload.splitlines():
  100. if patchtest_patterns.patchmetadata_regex.match(line):
  101. continue
  102. if TestPatch.prog.search_string(payload):
  103. break
  104. else:
  105. self.fail('A patch file has been added without a Signed-off-by tag: \'%s\'' % os.path.basename(newpatch.path))
  106. def test_cve_tag_format(self):
  107. for commit in TestPatch.commits:
  108. if patchtest_patterns.cve.search_string(
  109. commit.shortlog
  110. ) or patchtest_patterns.cve.search_string(commit.commit_message):
  111. tag_found = False
  112. for line in commit.payload.splitlines():
  113. if patchtest_patterns.cve_payload_tag.search_string(line):
  114. tag_found = True
  115. break
  116. if not tag_found:
  117. self.fail('Missing or incorrectly formatted CVE tag in patch file. Correct or include the CVE tag in the patch with format: "CVE: CVE-YYYY-XXXX"',
  118. commit=commit)