Skip to content

Instantly share code, notes, and snippets.

@cblte
Last active September 13, 2021 01:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cblte/5263dad3642a39a80e8f9c3f4bc44706 to your computer and use it in GitHub Desktop.
Save cblte/5263dad3642a39a80e8f9c3f4bc44706 to your computer and use it in GitHub Desktop.
PHP Script to execute shellscript (hookfile.sh) via Github Webhook in a secure way. Environment works for uberspace.de. Static site gen is hugo (gohugo.io)
#!/bin/bash
# --------------------
# place this file anywhere where it can be execute fromthe webhook.php file.
# make sure, you put the correct path to this file into the webhook.php
# webdirectory is a directory accessible via internet, but not the main websites directory
# .. ideally webdirectory is a access via subdomain
# --------------------
# set PATH
PATH=$HOME/bin:/usr/bin:$PATH
export PATH
# change into directory of hugo website
cd $HOME/hugo_websites/zn80-net
echo "Fetching latest commits in dir: " $(pwd)
git pull
# git reset --hard origin/main
# executing hugo command
$HOME/bin/hugo --minify --gc --cleanDestinationDir
if [ $code -eq 0 ]; then
echo "Hugo build successfull with return code" $?
rsync -az --delete public/ /var/www/virtual/cblte/html/
fi
# echo "Build succesfull. Syncing files"
cd -
<?php
/**
* Automated deploy from GitHub
*
* https://developer.github.com/webhooks/
* Template from ServerPilot (https://serverpilot.io/community/articles/how-to-automatically-deploy-a-git-repo-from-bitbucket.html)
* Hash validation from Craig Blanchette (http://isometriks.com/verify-github-webhooks-with-php)
*/
// ---------------------------------------------------------
// Variables
$secret = getenv('GH_DEPLOY_SECRET');
// ^^ for this, you need to add a secret string into
// your .htaccess file along this webhook script
// example: SetEnv GH_DEPLOY_SECRET 22ee4659d87ac19378f356df6f467151a82e6d18e0e9e9583dc42d76b2e55bbd
// you the string should be random. Use CyberChef or your password manager
$hookfile = '/home/<user>/bin/hookfile.sh';
// this is the path to the script you want to execute.
$logfile = '/var/www/virtual/<user>/<webdirectory>/deploy.log';
// this is the logfile. ideally a secret file you can access via web
// webdirectory is a directory accessible via internet, but not the main websites directory
// ideally webdirectory is a access via subdomain
// ---------------------------------------------------------
function log_append($message, $time = null)
{
global $logfile;
$time = $time === null ? time() : $time;
$date = date('Y-m-d H:i:s');
$pre = $date . ' (' . $_SERVER['REMOTE_ADDR'] . '): ';
file_put_contents($logfile, $pre . $message . "\n", FILE_APPEND);
}
function exec_command($command)
{
$output = array();
exec($command, $output);
log_append('EXEC: ' . $command);
foreach ($output as $line) {
log_append('SHELL: ' . $line);
}
}
// Validate hook secret
if ($secret !== NULL) {
// Get signature
$hub_signature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
// Make sure signature is provided
if (!isset($hub_signature)) {
log_append('ERROR: HTTP header "X-Hub-Signature" is missing.');
die('HTTP header "X-Hub-Signature" is missing.');
} elseif (!extension_loaded('hash')) {
log_append('ERROR: Missing "hash" extension to check the secret code validity.');
die('Missing "hash" extension to check the secret code validity.');
}
// Split signature into algorithm and hash
list($algo, $hash) = explode('=', $hub_signature, 2);
// Get payload
$payload = file_get_contents('php://input');
// Calculate hash based on payload and the secret
$payload_hash = hash_hmac($algo, $payload, $secret);
// Check if hashes are equivalent
if (!hash_equals($hash, $payload_hash)) {
// Kill the script or do something else here.
log_append('ERROR: Bad Secret');
die('Bad secret');
}
};
// Parse data from GitHub hook payload
$input = json_decode($_POST['payload']);
$commit_message = "";
if (empty($data->commits)) {
// When merging and pushing to GitHub, the commits array will be empty.
// In this case there is no way to know what branch was pushed to, so we will do an update.
$commit_message .= 'true';
} else {
foreach ($data->commits as $commit) {
$commit_message .= $commit->message;
}
}
if (!empty($commit_message)) {
log_append('INFO: Launching shell hook script...');
exec_command('sh '.$hookfile);
log_append('INFO: Shell hook script finished');
} else {
log_append('WARNING: Not commit message found. Command not executed.');
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment