link_sbom.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import argparse
  2. import json
  3. import os
  4. def parse_kv_arr(val):
  5. res = {}
  6. for kv in val.split(';'):
  7. k, v = kv.split('=')
  8. res[k] = v
  9. return res
  10. def deduce_name(path):
  11. name = os.path.basename(path)
  12. for prefix in ['contrib/libs/', 'contrib/python/py2/', 'contrib/python/py3/', 'contrib/python/']:
  13. if path.startswith(prefix):
  14. name = path[len(prefix):].replace('/', '-')
  15. break
  16. return name
  17. def parse_componenet(component):
  18. props = parse_kv_arr(component)
  19. path = props['path']
  20. ver = props['ver']
  21. res = {}
  22. res['type'] = 'library'
  23. res['name'] = deduce_name(path)
  24. res['version'] = ver
  25. res["properties"] = [
  26. {'name': 'arcadia_module_subdir', 'value': path},
  27. {'name': 'language', 'value': props['lang']}
  28. ]
  29. return res
  30. def main():
  31. parser = argparse.ArgumentParser(description='Generate SBOM data from used contribs info')
  32. parser.add_argument('-o', '--output', type=argparse.FileType('w', encoding='UTF-8'), help='resulting SBOM file', required=True)
  33. parser.add_argument('--vcs-info', type=argparse.FileType('r', encoding='UTF-8'), help='VCS information file', required=True)
  34. parser.add_argument('--mod-path', type=str, help='Path to module in arcadia', required=True)
  35. parser.add_argument('libinfo', metavar='N', type=str, nargs='*', help='libraries info for components section')
  36. args = parser.parse_args()
  37. vcs = json.load(args.vcs_info)
  38. res = {}
  39. res['$schema'] = "http://cyclonedx.org/schema/bom-1.5.schema.json"
  40. res["bomFormat"] = "CycloneDX"
  41. res["specVersion"] = "1.5"
  42. res["version"] = 1
  43. res["components"] = [parse_componenet(lib) for lib in args.libinfo]
  44. res["properties"] = [
  45. {'name': 'commit_hash', 'value': vcs['ARCADIA_SOURCE_HG_HASH'], 'arcadia_module_subdir': args.mod_path}
  46. ]
  47. if vcs.get('DIRTY', '') == 'dirty':
  48. res["properties"].append({'name': 'has_uncommited_changes', 'value': True})
  49. json.dump(res, args.output)
  50. args.output.close()
  51. if __name__ == '__main__':
  52. main()