Files

63 lines
2.4 KiB
PHP

<?php
declare(strict_types=1);
// Nginx independently requires Basic on this exact endpoint. No portal identity is created.
$configFile = getenv('INVESTMOZ_DELIVERY_CONFIG') ?: '/etc/investmoz-deploy/delivery.json';
$config = json_decode((string) @file_get_contents($configFile), true);
if (! is_array($config)) {
http_response_code(503);
exit('Deployment configuration unavailable');
}
$secret = @file_get_contents($config['webhook_secret_file']);
if (! is_string($secret) || trim($secret) === '') {
http_response_code(503);
exit('Webhook unavailable');
}
$body = (string) file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_GITEA_SIGNATURE'] ?? $_SERVER['HTTP_X_GOGS_SIGNATURE'] ?? '';
if (! preg_match('/\A[0-9a-f]{64}\z/i', $signature)
|| ! hash_equals(hash_hmac('sha256', $body, trim($secret)), strtolower($signature))) {
http_response_code(403);
exit('Invalid signature');
}
$event = $_SERVER['HTTP_X_GITEA_EVENT'] ?? $_SERVER['HTTP_X_GOGS_EVENT'] ?? '';
if ($event !== 'push') {
http_response_code(204);
exit;
}
$payload = json_decode($body, true);
if (! is_array($payload)) {
http_response_code(400);
exit('Invalid JSON');
}
if (($payload['repository']['full_name'] ?? '') !== $config['repository']
|| ($payload['ref'] ?? '') !== 'refs/heads/'.$config['branch']) {
http_response_code(204);
exit;
}
$commit = strtolower((string) ($payload['after'] ?? ''));
if (! preg_match('/\A[0-9a-f]{40}\z/', $commit) || $commit === str_repeat('0', 40)) {
http_response_code(400);
exit('Invalid revision');
}
$directory = $config['state_root'].'/requests';
$file = $directory.'/'.$commit.'.json';
// Atomic publication, exact commit identity; retries do not create duplicate requests.
$temporary = @tempnam($config['state_root'].'/incoming', 'incoming-');
if ($temporary === false) {
http_response_code(503);
exit('Queue unavailable');
}
chmod($temporary, 0640);
$data = json_encode(['commit' => $commit, 'ref' => $payload['ref'], 'received_at' => gmdate(DATE_ATOM)], JSON_THROW_ON_ERROR);
if (file_put_contents($temporary, $data) === false || ! rename($temporary, $file)) {
@unlink($temporary);
http_response_code(503);
exit('Queue unavailable');
}
// systemd.path observes the queue even if a previous build is still active.
http_response_code(202);
header('Content-Type: application/json');
echo json_encode(['accepted' => true, 'commit' => $commit]);