set_github_secret.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/usr/bin/env python
  2. # -*- encoding: utf-8 -*-
  3. '''
  4. @Contact : liuyuqi.gov@msn.cn
  5. @Time : 2023/11/13 14:29:00
  6. @License : Copyright © 2017-2022 liuyuqi. All Rights Reserved.
  7. @Desc : github api方式设置 Create or update a repository secret
  8. '''
  9. import requests
  10. import json,sys
  11. import base64
  12. class GithubPulbicKey:
  13. ''' Github public key '''
  14. def __init__(self, key_id: str, key: str):
  15. self.key_id = key_id
  16. self.key = key
  17. class GithubApi:
  18. ''' Github api '''
  19. _api_url = 'https://api.github.com'
  20. def __init__(self, owner: str, token: str, repo: str):
  21. self.owner = owner
  22. self.token = token
  23. self.repo = repo
  24. self.public_key = None
  25. self.sess = requests.Session()
  26. self.sess.headers.update({
  27. 'Accept': 'application/vnd.github.v3+json',
  28. 'X-GitHub-Api-Version': '2022-11-28',
  29. 'Authorization': f'Bearer {self.token}'
  30. })
  31. def get_repo_public_key(self) -> GithubPulbicKey:
  32. ''' Get a repository public key
  33. {
  34. "key_id": "012345678912345678",
  35. "key": "xx+dB7TJyvv1234"
  36. }
  37. '''
  38. url = f'{self._api_url}/repos/{self.owner}/{self.repo}/actions/secrets/public-key'
  39. response = self.sess.get(url)
  40. print(f'get public key response: {response.text}')
  41. if response.status_code == 200:
  42. res_json = response.json()
  43. self.public_key = GithubPulbicKey(
  44. res_json['key_id'], res_json['key'])
  45. return self.public_key
  46. else:
  47. print("Failed to get repository public key.")
  48. print(f"Response status code: {response.status_code}")
  49. print(f"Response body: {response.text}")
  50. return None
  51. @staticmethod
  52. def _base64encode(value):
  53. """
  54. :param value: byte, encrypted message
  55. :return: string
  56. """
  57. if sys.version_info <= (3, 1):
  58. return base64.encodestring(value).decode("utf-8")
  59. else:
  60. return base64.encodebytes(value).decode("utf-8")
  61. @staticmethod
  62. def encrypt_secret_value(value: str, public_key: str):
  63. ''' Value for your secret, encrypted with LibSodium using the public key retrieved from
  64. the Get a repository public key endpoint.
  65. https://github.com/anna-money/workflow-tools/blob/8a94d18254183847d3706e5a610739b40b48c4e6/workflow_tools/secret.py#L63
  66. '''
  67. public_key_encoded = public.PublicKey(public_key.encode("utf-8"), encoding.Base64Encoder())
  68. sealed_box = public.SealedBox(public_key_encoded)
  69. encrypted = sealed_box.encrypt(value.encode("utf-8"))
  70. encrypted_string = GithubApi._base64encode(encrypted)
  71. # In Python 3.1+ base64.encodebytes inserts "\n" after every 76 bytes of output and
  72. # adds a trailing newline character to follow RFC 2045
  73. # https://docs.python.org/3/library/base64.html#base64.encodebytes
  74. # To make sure GitHub API accepts payload, remove "\n" from the encrypted value.
  75. result = encrypted_string.replace("\n", "")
  76. return result
  77. def set_update_github_secret(self, key: str, value: str):
  78. url = f'{self._api_url}/repos/{self.owner}/{self.repo}/actions/secrets/{key}'
  79. if self.public_key is None:
  80. self.get_repo_public_key()
  81. if self.public_key is not None:
  82. secret_value = self.encrypt_secret_value(
  83. value, self.public_key.key)
  84. data = {
  85. 'encrypted_value': secret_value,
  86. 'key_id': self.public_key.key_id
  87. }
  88. response = self.sess.put(url, json=data)
  89. if response.status_code == 204:
  90. print(f"GitHub secret: {key} updated successfully!")
  91. else:
  92. print("Failed to update GitHub secret.")
  93. print(f"Response status code: {response.status_code}")
  94. print(f"Response body: {response.text}")
  95. if __name__ == '__main__':
  96. with open("account.json", "r") as file:
  97. data = json.load(file)
  98. owner = data["owner"]
  99. token = data["token"]
  100. repo = data["repo"]
  101. github_api = GithubApi(owner=owner, token=token, repo=repo)
  102. for i in range(data["secret"]):
  103. key = i["key"]
  104. value = i["value"]
  105. github_api.set_update_github_secret(key, value)