GitHub项目监控

目录

  • github开放平台
    • 接口限流
    • 调用git命令和gitpython库
      • subprocess调用git
      • gitpython库调用git
    • go调用git的库
  • 实例
    • 监控某个仓库的更新状态

对于常用Github的用户来说,经常有一些自动化的需求。比如监控某些项目的更新情况并实时拉取,比如监控github全网上传的代码是否携带了公司的APIKEY,SECRETKEY等…

github开放平台

github平台也提供了自己的REST API文档:https://docs.github.com/zh/rest?apiVersion=2022-11-28

GitHub项目监控_第1张图片

接口限流

GitHub API 响应会对速率限制进行分类,主要分为:

  • core 对象提供 REST API 中所有非搜索相关资源的速率限制状态。

  • search 对象提供用于搜索的 REST API 的速率限制状态(代码搜索除外)。 有关详细信息,请参阅“搜索”。

  • code_search 对象提供用于搜索代码的 REST API 的速率限制状态。 有关详细信息,请参阅“搜索”。

  • graphql 对象提供 GraphQL API 的速率限制状态。

  • integration_manifest 对象提供 POST /app-manifests/{code}/conversions 操作的速率限制状态。 有关详细信息,请参阅“从清单注册 GitHub 应用”。

  • dependency_snapshots 对象提供将快照提交到依赖项关系图的速率限制状态。 有关详细信息,请参阅“依赖项关系图”。
  • code_scanning_upload 对象提供用于将 SARIF 结果上传到代码扫描的速率限制状态。 有关详细信息,请参阅“将 SARIF 文件上传到 GitHub”。

  • actions_runner_registration 对象提供在 GitHub Actions 中注册自托管运行器的速率限制状态。 有关详细信息,请参阅“自托管运行程序”。

只需要GET请求:https://api.github.com/rate_limit即可查看限流

请求头里面不携带token,则显示匿名用户的配置:

GitHub项目监控_第2张图片
获取token需要到开发者配置中生成Token
GitHub项目监控_第3张图片
然后在请求头里携带即可:
GitHub项目监控_第4张图片
格式:Bearer

GitHub项目监控_第5张图片

调用git命令和gitpython库

与github交互,除了使用rest api外,还可以通过调用git客户端来进行交互。

在Python中,有几个库可以用于操作Git:

  1. GitPython: GitPython 是一个强大的Python库,它允许你在Python程序中直接与Git仓库进行交互。它提供了一个高级接口,可以执行各种Git操作,如克隆仓库、提交更改、创建分支等等。

    官方网站:https://gitpython.readthedocs.io/

    安装方法:

    pip install gitpython
    

    示例用法:

    from git import Repo
    
    # 克隆仓库
    repo = Repo.clone_from('https://github.com/username/repo.git', '/path/to/destination')
    
    # 获取当前分支
    current_branch = repo.active_branch
    
    # 提交更改
    repo.index.add(['file1', 'file2'])
    repo.index.commit('Commit message')
    
    # 创建分支
    new_branch = repo.create_head('new_branch')
    
    # 等等...
    
  2. GitDB: GitDB 是一个用于读取Git仓库中的对象(commit、tree、blob等)的库。它是GitPython的底层依赖库之一。

    官方网站:https://gitdb.readthedocs.io/

    安装方法:

    pip install gitdb
    
  3. Pygit2: Pygit2 是一个用于直接访问libgit2库的Python绑定,libgit2是一个纯C实现的Git库。它提供了高性能的Git操作,但相对于GitPython来说,它的接口可能更底层一些。

    官方网站:http://www.pygit2.org/

    安装方法:

    pip install pygit2
    

    示例用法:

    import pygit2
    
    repo = pygit2.Repository('/path/to/repository')
    
    # 获取提交记录
    commits = list(repo.walk(repo.head.target, pygit2.GIT_SORT_TIME))
    
    # 提交更改
    index = repo.index
    index.add('file1')
    tree = index.write_tree()
    author = pygit2.Signature('Your Name', '[email protected]')
    committer = pygit2.Signature('Your Name', '[email protected]')
    commit = repo.create_commit('HEAD', author, committer, 'Commit message', tree, [repo.head.target])
    
    # 等等...
    

subprocess调用git

import subprocess

# 仓库的ssh_url
ssh_url = "[email protected]:Generalzy/go-csv.git"

# 拉取仓库
subprocess.run(["git", "clone", ssh_url, "-b", "master"], shell=True)

GitHub项目监控_第6张图片
如同手敲git命令一般,就clone到了仓库的代码。

对于仓库的拉取,也是一样的道理

# pull
subprocess.run(["cd", "go-csv", "&&", "git", "pull", "origin", "master"], shell=True)

GitHub项目监控_第7张图片
也可以把操作封装到lua,shell,exe等文件进行调用,不再赘述。

gitpython库调用git

gitpython 是一个用于操作Git版本控制系统的Python库。它提供了一个Pythonic的API,可以让你在Python中轻松地执行各种Git操作,例如克隆仓库、提交代码、分支管理等。

以下是一些 gitpython 的基本用法和功能:

  1. 克隆仓库

    from git import Repo
    
    repo_url = "https://github.com/username/repository.git"
    local_path = "/path/to/local/repository"
    
    repo = Repo.clone_from(repo_url, local_path)
    
  2. 打开现有仓库

    from git import Repo
    
    local_path = "/path/to/local/repository"
    
    repo = Repo(local_path)
    
  3. 获取仓库信息

    repo_url = repo.remote().url
    branch_name = repo.active_branch.name
    
  4. 查看当前分支的提交历史

    for commit in repo.iter_commits():
        print(f"{commit.hexsha} {commit.message}")
    
  5. 提交代码

    index = repo.index
    index.add(["file1.txt", "file2.txt"])
    index.commit("Commit message")
    
  6. 创建和切换分支

    branch = repo.create_head("new_branch")
    repo.head.reference = branch
    
  7. 拉取最新代码

    origin = repo.remotes.origin
    origin.pull()
    
  8. 推送本地分支到远程

    origin = repo.remotes.origin
    origin.push()
    
  9. 查看未提交的更改

    untracked_files = repo.untracked_files
    modified_files = [item.a_path for item in repo.index.diff(None)]
    
  10. 检查是否存在未提交的更改

    has_uncommitted_changes = repo.is_dirty(untracked_files=True)
    

gitpython 提供了许多方便的方法和属性,使得在Python中进行Git操作变得简单而直观。

更多关于 gitpython 的详细信息,可以查阅官方文档:https://gitpython.readthedocs.io。

go调用git的库

Go语言中有许多用于操作GitHub的包或库,它们提供了与GitHub API 交互的功能,可以用于创建、读取、更新和删除GitHub仓库,管理问题、拉取请求等等。

以下是一些常用的Go语言库,可以用于与GitHub进行交互:

  1. go-github: 这是一个由 GitHub 提供的官方 Go 语言库,用于访问 GitHub API。它提供了与 GitHub API 交互的功能,包括创建仓库、管理问题、处理拉取请求等。

    项目地址:https://github.com/google/go-github

  2. go-git: 这是一个纯Go实现的Git库,可以用于在Go程序中执行Git操作,包括克隆仓库、提交更改等。虽然它不是直接用于操作GitHub API,但可以在本地操作Git仓库后再与GitHub进行交互。

    项目地址:https://github.com/go-git/go-git

  3. gh: 这是一个命令行工具和Go库,用于与GitHub进行交互。它提供了一个简单的命令行界面,可以用于执行各种GitHub操作。

    项目地址:https://github.com/cli/cli

  4. github.com/google/go-github/github: 这是 go-github 库的一部分,提供了对 GitHub API 的类型定义,可以在你的Go程序中使用这些类型来与GitHub API进行交互。

    项目地址:https://github.com/google/go-github

实例

监控某个仓库的更新状态

为了能够获取github上的项目的更新时间,我们需要调用github的一个API(参考:https://docs.github.com/zh/rest/repos/repos?apiVersion=2022-11-28#get-a-repository):

https://api.github.com/repos/拥有者/仓库名

GitHub项目监控_第8张图片
比如调用我的一个仓库:https://github.com/Generalzy/go-csv,API就是:https://api.github.com/repos/Generalzy/go-csv

GitHub项目监控_第9张图片
与Github线上项目对比更新时间,将其格式化为10位时间戳,这样对比起来非常方便,最后返回的时候只需要返回是否需要更新即可。

如果有需要更新的项目,让其自动下载:

比如下载zip包:https://github.com/{仓库}/archive/master.zip

import requests

with open("./master.zip","wb") as writer:
	response = requests.get("https://github.com/{仓库}/archive/master.zip",stream=True)
	for chunk in response.iter_content(1024):
		writer.write(chunk)

# 全部解压
with zipfile.Zipfile("master.zip") as XDD:
	XDD.extractall()

或者也可以访问:/repos/{owner}/{repo}/activity

列出存储库更改的详细历史记录,例如推送、合并、强制推送和分支更改,并将这些更改与提交和用户相关联。

GitHub项目监控_第10张图片
index = 0的记录就是当前仓库最后一条更新的记录。

以某EXP/POC仓库为例,给出源码:

import os
import re
import sys
import ujson
import urllib3
import requests
from git import Repo
from dateutil.parser import parse

urllib3.disable_warnings()

# 存放zip包和json文件的位置
LOCAL_REPOS_DIR = "."

TYPE_POC = "poc"
TYPE_EXP = "exp"

# https://api.github.com/repos/用户名/库名
GITHUB_API_PREFIX = "https://api.github.com/repos"
GITHUB_WEB_PREFIX = "https://github.com"
GITHUB_DOWNLOAD_SUFFIX = "/archive/master.zip"

# CVE/CNVD/CNNVD的正则
CNVD_REGEXP = r"CNVD-\d{4}-\d{4,5}"
CNNVD_REGEXP = r"CNNVD-\d{4}-\d{4,5}"
CVE_REGEXP = r"CVE-\d{4}-\d{4,}"

src = {
    "url": "https://github.com/RhinoSecurityLabs/CVEs",
    "name": "CVEs",
    "type": "exp"
}


def walk(path: str):
    paths = []

    for file in os.walk(path):
        left, mid, right = file

        for filename in right:
            paths.append(os.path.join(left, filename))

    return paths


def dump(obj, fp):
    ujson.dump(obj, fp, ensure_ascii=False, indent=4)


def scan_cve(line: str) -> str:
    result = re.search(CVE_REGEXP, line, re.I | re.M | re.DOTALL)
    return result.group() if result else ""


def scan_cnvd(line: str) -> str:
    result = re.search(CNVD_REGEXP, line, re.I | re.M | re.DOTALL)
    return result.group() if result else ""


def scan_cnnvd(line: str) -> str:
    result = re.search(CNNVD_REGEXP, line, re.I | re.M | re.DOTALL)
    return result.group() if result else ""


def disclosure_parse(path: str, url: str, name: str, type_: str, dst: str):
    """
    CVEs特征:
        1. CVE编号作文件夹
        2. README.md第一行可以作为title
    """
    pass


def compare_and_swap(repo_url: str, repo_name: str):
    # 比较远程和本地的更新时间
    # 如果远程新就更新
    api_url = repo_url.replace(GITHUB_WEB_PREFIX, GITHUB_API_PREFIX)
    response = requests.get(api_url, verify=False)
    if response.status_code == 200:
        data = response.json()

        update_time = data["updated_at"]
        update_time = parse(update_time)
        # 对比本地仓库最后更新时间
        filepath = os.path.join(LOCAL_REPOS_DIR, repo_name)
        if not os.path.exists(filepath):
            # ssh克隆
            clone_url = data["clone_url"]
            # 使用 gitpython 来克隆远程仓库
            Repo.clone_from(clone_url, filepath)
            # 返回更新
            return True

        info = os.stat(filepath)

        local_mtime = int(info.st_mtime)
        remote_mtime = int(update_time.timestamp())
        print(f"remote:{remote_mtime},local:{local_mtime}, remote>local? {remote_mtime > local_mtime}")
        if local_mtime < remote_mtime:
            # 打开本地仓库
            repo = Repo(filepath)
            # 获取远程仓库对象
            origin = repo.remotes.origin
            # 执行拉取操作
            origin.pull()
            return True
        else:
            return False
    else:
        return False


def handler(url: str, name: str, type_: str, dst: str):
    swap = compare_and_swap(url, name)
    if swap:
        filepath = os.path.join(LOCAL_REPOS_DIR, name)
        # 解析仓库
        disclosure_parse(filepath, url, name, type_, dst)


if __name__ == '__main__':
    assert len(sys.argv) > 1, "Hey bro? Do you forget to input json filepath?"

    dst = sys.argv[-1]
    handler(url=src["url"], name=src["name"], type_=src["type"], dst=dst)

不管是结合linux的cron还是k8s的cronjob,都可以监控到这个仓库的变化并且拉取最新代码,并且监控Github仓库可以做成一套类似的模板,只有解析器需要自己自定义,其他代码均可以一键生成。

并且,在此基础上还可以扩展一些通知接口,比如仓库更新后发送邮件给监听者,发送微信或短信消息给监听者…

你可能感兴趣的:(python,github)