gen_provenance_metadata_test.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (C) 2022 The Android Open Source Project
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. import hashlib
  17. import logging
  18. import os
  19. import subprocess
  20. import tempfile
  21. import unittest
  22. import google.protobuf.text_format as text_format
  23. import provenance_metadata_pb2
  24. logger = logging.getLogger(__name__)
  25. def run(args, verbose=None, **kwargs):
  26. """Creates and returns a subprocess.Popen object.
  27. Args:
  28. args: The command represented as a list of strings.
  29. verbose: Whether the commands should be shown. Default to the global
  30. verbosity if unspecified.
  31. kwargs: Any additional args to be passed to subprocess.Popen(), such as env,
  32. stdin, etc. stdout and stderr will default to subprocess.PIPE and
  33. subprocess.STDOUT respectively unless caller specifies any of them.
  34. universal_newlines will default to True, as most of the users in
  35. releasetools expect string output.
  36. Returns:
  37. A subprocess.Popen object.
  38. """
  39. if 'stdout' not in kwargs and 'stderr' not in kwargs:
  40. kwargs['stdout'] = subprocess.PIPE
  41. kwargs['stderr'] = subprocess.STDOUT
  42. if 'universal_newlines' not in kwargs:
  43. kwargs['universal_newlines'] = True
  44. if verbose:
  45. logger.info(" Running: \"%s\"", " ".join(args))
  46. return subprocess.Popen(args, **kwargs)
  47. def run_and_check_output(args, verbose=None, **kwargs):
  48. """Runs the given command and returns the output.
  49. Args:
  50. args: The command represented as a list of strings.
  51. verbose: Whether the commands should be shown. Default to the global
  52. verbosity if unspecified.
  53. kwargs: Any additional args to be passed to subprocess.Popen(), such as env,
  54. stdin, etc. stdout and stderr will default to subprocess.PIPE and
  55. subprocess.STDOUT respectively unless caller specifies any of them.
  56. Returns:
  57. The output string.
  58. Raises:
  59. ExternalError: On non-zero exit from the command.
  60. """
  61. proc = run(args, verbose=verbose, **kwargs)
  62. output, _ = proc.communicate()
  63. if output is None:
  64. output = ""
  65. if verbose:
  66. logger.info("%s", output.rstrip())
  67. if proc.returncode != 0:
  68. raise RuntimeError(
  69. "Failed to run command '{}' (exit code {}):\n{}".format(
  70. args, proc.returncode, output))
  71. return output
  72. def run_host_command(args, verbose=None, **kwargs):
  73. host_build_top = os.environ.get("ANDROID_BUILD_TOP")
  74. if host_build_top:
  75. host_command_dir = os.path.join(host_build_top, "out/host/linux-x86/bin")
  76. args[0] = os.path.join(host_command_dir, args[0])
  77. return run_and_check_output(args, verbose, **kwargs)
  78. def sha256(s):
  79. h = hashlib.sha256()
  80. h.update(bytearray(s, 'utf-8'))
  81. return h.hexdigest()
  82. class ProvenanceMetaDataToolTest(unittest.TestCase):
  83. def test_gen_provenance_metadata(self):
  84. artifact_content = "test artifact"
  85. artifact_file = tempfile.mktemp()
  86. with open(artifact_file,"wt") as f:
  87. f.write(artifact_content)
  88. attestation_file = artifact_file + ".intoto.jsonl"
  89. with open(attestation_file, "wt") as af:
  90. af.write("attestation file")
  91. metadata_file = tempfile.mktemp()
  92. cmd = ["gen_provenance_metadata"]
  93. cmd.extend(["--module_name", "a"])
  94. cmd.extend(["--artifact_path", artifact_file])
  95. cmd.extend(["--install_path", "b"])
  96. cmd.extend(["--metadata_path", metadata_file])
  97. output = run_host_command(cmd)
  98. self.assertEqual(output, "")
  99. with open(metadata_file,"rt") as f:
  100. data = f.read()
  101. provenance_metadata = provenance_metadata_pb2.ProvenanceMetadata()
  102. text_format.Parse(data, provenance_metadata)
  103. self.assertEqual(provenance_metadata.module_name, "a")
  104. self.assertEqual(provenance_metadata.artifact_path, artifact_file)
  105. self.assertEqual(provenance_metadata.artifact_install_path, "b")
  106. self.assertEqual(provenance_metadata.artifact_sha256, sha256(artifact_content))
  107. self.assertEqual(provenance_metadata.attestation_path, attestation_file)
  108. os.remove(artifact_file)
  109. os.remove(metadata_file)
  110. os.remove(attestation_file)
  111. if __name__ == '__main__':
  112. unittest.main(verbosity=2)