diff --git a/deploy_config.py b/deploy_config.py index a1e7354..dd8c3ba 100644 --- a/deploy_config.py +++ b/deploy_config.py @@ -6,8 +6,11 @@ if __name__ == "__main__": # make sure git does not block giving pw prompts, git 2.3+ only os.environ["GIT_TERMINAL_PROMPT"] = "0" +# needs to be a byte like object +GITHUB_SECRET = b"changetosomethingrandomlong" + RUNNERS = { - # name of the runner, avoid spaces and other obscure cahracters + # unique name of the runner, avoid spaces and other obscure characters "website_master": { # directory where building takes place, will be created if not there diff --git a/develop_main.py b/develop_main.py index 823d27c..ab1f3a7 100755 --- a/develop_main.py +++ b/develop_main.py @@ -1,6 +1,7 @@ #! /usr/bin/env python3 from pelican_deploy import DeploymentRunner +import pelican_deploy.webhookbottle import deploy_config import logging @@ -10,5 +11,9 @@ runners = {name: DeploymentRunner(name, conf) for name, conf in deploy_config.RUNNERS.items()} if __name__ == "__main__": - for r in runners.values(): - r.build_blocking() + #for r in runners.values(): + # r.build_blocking() + pelican_deploy.webhookbottle.set_runners(**runners) + pelican_deploy.webhookbottle.set_github_secret(deploy_config.GITHUB_SECRET) + pelican_deploy.webhookbottle.devrun() + diff --git a/pelican_deploy/webhookbottle.py b/pelican_deploy/webhookbottle.py new file mode 100644 index 0000000..9e9000b --- /dev/null +++ b/pelican_deploy/webhookbottle.py @@ -0,0 +1,66 @@ +from bottle import route, run, template, request, post, Bottle, HTTPError +import logging +import hmac +import hashlib +import sys + +log = logging.getLogger(__name__) + +app = Bottle() + + +def set_runners(**name_runner_mapping): + app.config["deploy.runners"] = name_runner_mapping + +def set_github_secret(secret): + app.config["deploy.github_secret"] = secret + +def _get_runner(name): + try: + runners = app.config["deploy.runners"] + except KeyError as e: + sys.exit("you have to call set_runners first") + + return runners[name] + +def _start_build(name, push_ref): + runner = _get_runner(name) + branch = runner.git_branch + if push_ref in (branch, "refs/heads/{}".format(branch)): + runner.build(abort_running=True) + else: + log.debug("Runner %s was not invoked, push to branch %s, runner for %s", + runner.name, push_ref, branch) + +def _verify_github_signature(sighdr, body): + try: + secret = app.config["deploy.github_secret"] + except KeyError as e: + raise RuntimeError("github secret not set!") from e + + signature = 'sha1=' + hmac.new(secret, body, hashlib.sha1).hexdigest() + return hmac.compare_digest(sighdr, signature) + + +@app.post('/github/') +def index(name): + sighdr = request.headers.get("X-Hub-Signature", "") + if not _verify_github_signature(sighdr, request.body.read()): + log.error("Github request for %s faild to validate. " + "Have you configured the secret correctly?", name) + raise HTTPError(status=403) + + evtype = request.headers.get('X-GitHub-Event') + if evtype != "push": + log.info("Github sent event of type %s to %s, ignoring", evtype, name) + return "Ignored" + + log.info("Got Github event of type %s to %s", evtype, name) + + hook = request.json + + _start_build(name, hook.get("ref", "")) + return "Success!" + +def devrun(): + run(app=app, host='0.0.0.0', port=4000, debug=True)