|  | 
|  | 1 | +import logging | 
|  | 2 | +import os | 
|  | 3 | +import pathlib | 
|  | 4 | +import typing | 
|  | 5 | +from urllib.parse import urlparse | 
|  | 6 | + | 
|  | 7 | +from guarddog.analyzer.analyzer import Analyzer | 
|  | 8 | +from guarddog.ecosystems import ECOSYSTEM | 
|  | 9 | +from guarddog.scanners.scanner import PackageScanner | 
|  | 10 | + | 
|  | 11 | +log = logging.getLogger("guarddog") | 
|  | 12 | + | 
|  | 13 | + | 
|  | 14 | +class GithubActionScanner(PackageScanner): | 
|  | 15 | +    def __init__(self) -> None: | 
|  | 16 | +        super().__init__(Analyzer(ECOSYSTEM.GITHUB_ACTION)) | 
|  | 17 | + | 
|  | 18 | +    def download_and_get_package_info(self, directory: str, package_name: str, version=None) -> typing.Tuple[dict, str]: | 
|  | 19 | +        repo = self._get_repo(package_name) | 
|  | 20 | +        tarball_url = self._get_git_tarball_url(repo, version) | 
|  | 21 | + | 
|  | 22 | +        log.debug(f"Downloading GitHub Action source from {tarball_url}") | 
|  | 23 | + | 
|  | 24 | +        file_extension = pathlib.Path(tarball_url).suffix | 
|  | 25 | +        if file_extension == "": | 
|  | 26 | +            file_extension = ".zip" | 
|  | 27 | + | 
|  | 28 | +        zippath = os.path.join(directory, package_name.replace("/", "-") + file_extension) | 
|  | 29 | +        unzippedpath = zippath.removesuffix(file_extension) | 
|  | 30 | +        self.download_compressed(tarball_url, zippath, unzippedpath) | 
|  | 31 | + | 
|  | 32 | +        return {}, unzippedpath | 
|  | 33 | + | 
|  | 34 | +    def _get_repo(self, url: str) -> str: | 
|  | 35 | +        parsed_url = urlparse(url) | 
|  | 36 | + | 
|  | 37 | +        if parsed_url.hostname and parsed_url.hostname != "github.com": | 
|  | 38 | +            raise ValueError("Invalid GitHub repo URL: " + url) | 
|  | 39 | + | 
|  | 40 | +        path = parsed_url.path.removesuffix(".git").strip("/") | 
|  | 41 | + | 
|  | 42 | +        if path.count("/") != 1: | 
|  | 43 | +            raise ValueError("Invalid GitHub repo name: " + path) | 
|  | 44 | + | 
|  | 45 | +        return path | 
|  | 46 | + | 
|  | 47 | +    def _get_git_tarball_url(self, repo: str, version=None) -> str: | 
|  | 48 | +        if not version: | 
|  | 49 | +            return f"https://api.github.com/repos/{repo}/zipball" | 
|  | 50 | +        else: | 
|  | 51 | +            return f"https://github.com/{repo}/archive/refs/tags/{version}.zip" | 
0 commit comments