@@ -22,36 +22,30 @@ def is_sha1(sha: str) -> bool:
2222 return len (sha ) == 40 and all (c in "0123456789abcdef" for c in sha .lower ())
2323
2424
25- def github_tag_to_commit (owner : str , repo : str , tag : str ) -> str :
26- """Convert a GitHub tag to a commit hash.
27-
25+ def _get_github_tag_info (owner : str , repo : str , tag : str , headers : dict ) -> dict :
26+ """
27+ Get information about a GitHub tag using GitHub's REST API.
2828 Args:
29- tag (str): The GitHub tag.
29+ owner (str): Repository owner
30+ repo (str): Repository name
31+ tag (str): Tag name/reference
32+ headers (dict): Headers to include in the API request
3033
3134 Returns:
32- str: The commit hash corresponding to the tag.
33- """
34- return get_tag_commit_sha (owner , repo , tag )
35-
36-
37- def validate_tag_url (url : str ) -> None :
38- """Validate a GitHub API URL to prevent server-side request forgery"""
39- if not url .startswith ("https://api.github.com" ):
40- raise ValueError (f"Invalid GitHub API URL '{ url } " )
41- if not is_sha1 (url .split ("/" )[- 1 ]):
42- raise ValueError (f"Invalid SHA1 hash in URL '{ url } '" )
35+ dict: The JSON response from the GitHub API
4336
37+ Raises:
38+ requests.exceptions.RequestException: If the API request fails
39+ """
40+ logging .debug ("Resolving GitHub tag %s in repo %s/%s to commit SHA" , tag , owner , repo )
4441
45- def get_github_token () -> str | None :
46- """Get GitHub token from environment variable if available"""
47- if "GITHUB_TOKEN" in os .environ and os .environ ["GITHUB_TOKEN" ]:
48- logging .debug ("GitHub token found in environment" )
49- return str (os .environ ["GITHUB_TOKEN" ])
50- logging .debug ("No GitHub token found, proceeding unauthenticated" )
51- return None
42+ url = f"https://api.github.com/repos/{ owner } /{ repo } /git/ref/tags/{ tag } "
43+ response = requests .get (url , headers = headers , timeout = 30 )
44+ response .raise_for_status ()
45+ return response .json ()
5246
5347
54- def get_tag_commit_sha (owner : str , repo : str , tag : str ) -> str :
48+ def github_tag_to_commit (owner : str , repo : str , tag : str ) -> str :
5549 """Convert a GitHub tag to a commit hash using GitHub's REST API.
5650
5751 Args:
@@ -65,16 +59,31 @@ def get_tag_commit_sha(owner: str, repo: str, tag: str) -> str:
6559 Raises:
6660 requests.exceptions.RequestException: If the API request fails
6761 """
68- token = get_github_token ()
62+ # Set Headers for GitHub API request
6963 headers = {"Accept" : "application/vnd.github.v3+json" }
64+ token = get_github_token ()
7065 if token :
7166 headers ["Authorization" ] = f"Bearer { token } "
7267
73- url = f"https://api.github.com/repos/{ owner } /{ repo } /git/ref/tags/{ tag } "
74- response = requests .get (url , headers = headers , timeout = 30 )
75- response .raise_for_status ()
68+ # First try to get the tag info directly
69+ try :
70+ data = _get_github_tag_info (owner , repo , tag , headers )
71+ # If the tag is not found and does not start with 'v', try again with 'v' prefix. Needed for
72+ # GitHub actions and cdxgen
73+ except requests .exceptions .RequestException as e :
74+ status_code = getattr (e .response , "status_code" , None )
75+ if status_code == 404 and not tag .startswith ("v" ):
76+ logging .debug ("Tag %s not found, retrying with 'v' prefix" , tag )
77+ try :
78+ data = _get_github_tag_info (owner , repo , f"v{ tag } " , headers )
79+ except requests .exceptions .RequestException :
80+ if getattr (e .response , "status_code" , None ) == 404 :
81+ logging .error ("Tag %s (or v%s) not found in repo %s/%s" , tag , tag , owner , repo )
82+ return tag
83+ raise e from e
84+ else :
85+ raise
7686
77- data = response .json ()
7887 # Tag refs point to annotated tags first, which then point to commits
7988 if data ["object" ]["type" ] == "tag" :
8089 # Get the commit URL from the annotated tag
@@ -86,3 +95,20 @@ def get_tag_commit_sha(owner: str, repo: str, tag: str) -> str:
8695
8796 # Lightweight tags point directly to commits
8897 return data ["object" ]["sha" ]
98+
99+
100+ def validate_tag_url (url : str ) -> None :
101+ """Validate a GitHub API URL to prevent server-side request forgery"""
102+ if not url .startswith ("https://api.github.com" ):
103+ raise ValueError (f"Invalid GitHub API URL '{ url } " )
104+ if not is_sha1 (url .split ("/" )[- 1 ]):
105+ raise ValueError (f"Invalid SHA1 hash in URL '{ url } '" )
106+
107+
108+ def get_github_token () -> str | None :
109+ """Get GitHub token from environment variable if available"""
110+ if "GITHUB_TOKEN" in os .environ and os .environ ["GITHUB_TOKEN" ]:
111+ logging .debug ("GitHub token found in environment" )
112+ return str (os .environ ["GITHUB_TOKEN" ])
113+ logging .debug ("No GitHub token found, proceeding unauthenticated" )
114+ return None
0 commit comments