Add webhook-triggered rebuilds for Pelican sites
Adds a webhook-deploy service that listens for Codeberg push events and triggers per-site nixos-rebuild runs. Skips rebuilds if the flake lock revision is unchanged. Fixes root SSH client config so nix flake update can reach Codeberg using the existing deploy key. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cd4d53386c
commit
bb419a13af
4 changed files with 94 additions and 2 deletions
|
|
@ -48,6 +48,7 @@
|
|||
./modules/services/nostr-rs-relay.nix
|
||||
./modules/services/podman.nix
|
||||
./modules/services/static-sites
|
||||
./modules/services/webhook-deploy.nix
|
||||
./modules/users/tobias.nix
|
||||
];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ randogoth.com, www.randogoth.com {
|
|||
}
|
||||
|
||||
sublunar.space, www.sublunar.space {
|
||||
handle /hooks/* {
|
||||
reverse_proxy localhost:9000
|
||||
}
|
||||
root * /var/www/sublunar.space/public
|
||||
encode zstd gzip
|
||||
file_server
|
||||
|
|
|
|||
87
modules/services/webhook-deploy.nix
Normal file
87
modules/services/webhook-deploy.nix
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
sites = [
|
||||
{ name = "sublunar"; input = "sublunar"; }
|
||||
{ name = "tobias-raayoni-last"; input = "flux_vision"; }
|
||||
{ name = "nmns"; input = "nfc_web"; }
|
||||
];
|
||||
|
||||
# Template hooks.json with a placeholder secret — real secret injected at
|
||||
# service start time from the sops-managed file.
|
||||
hooksTemplate = pkgs.writeText "webhook-hooks-template.json" (builtins.toJSON
|
||||
(map (site: {
|
||||
id = "rebuild-${site.name}";
|
||||
execute-command = "/run/current-system/sw/bin/systemctl";
|
||||
pass-arguments-to-command = [
|
||||
{ source = "string"; name = "start"; }
|
||||
{ source = "string"; name = "--no-block"; }
|
||||
{ source = "string"; name = "update-${site.name}"; }
|
||||
];
|
||||
response-message = "Queued rebuild of ${site.name}";
|
||||
trigger-rule.match = {
|
||||
type = "payload-hmac-sha256";
|
||||
secret = "placeholder";
|
||||
parameter = { source = "header"; name = "X-Gitea-Signature"; };
|
||||
};
|
||||
}) sites)
|
||||
);
|
||||
|
||||
# Writes /run/webhook-deploy/hooks.json with the real secret at startup.
|
||||
makeHooks = pkgs.writeShellScript "make-webhook-hooks" ''
|
||||
set -euo pipefail
|
||||
${pkgs.jq}/bin/jq \
|
||||
--arg s "$(cat ${config.sops.secrets.webhook_secret.path})" \
|
||||
'map(.["trigger-rule"].match.secret = $s)' \
|
||||
${hooksTemplate} > /run/webhook-deploy/hooks.json
|
||||
'';
|
||||
|
||||
updateScript = site: pkgs.writeShellScript "do-update-${site.name}" ''
|
||||
set -euo pipefail
|
||||
cd /etc/nixos
|
||||
OLD=$(${pkgs.jq}/bin/jq -r '.nodes.${site.input}.locked.rev' flake.lock)
|
||||
nix flake update ${site.input}
|
||||
NEW=$(${pkgs.jq}/bin/jq -r '.nodes.${site.input}.locked.rev' flake.lock)
|
||||
if [ "$OLD" = "$NEW" ]; then
|
||||
echo "${site.name}: no change, skipping rebuild"
|
||||
exit 0
|
||||
fi
|
||||
echo "${site.name}: updated $OLD -> $NEW, rebuilding"
|
||||
nixos-rebuild switch --flake /etc/nixos#bucur
|
||||
'';
|
||||
in
|
||||
{
|
||||
sops.secrets.webhook_secret = {
|
||||
owner = "root";
|
||||
mode = "0400";
|
||||
};
|
||||
|
||||
# System-wide SSH client config so root can reach Codeberg via the deploy key.
|
||||
programs.ssh.extraConfig = ''
|
||||
Host codeberg.org
|
||||
IdentityFile /etc/ssh/codeberg_id_ed25519
|
||||
StrictHostKeyChecking accept-new
|
||||
'';
|
||||
|
||||
systemd.services = lib.listToAttrs
|
||||
(map (site: lib.nameValuePair "update-${site.name}" {
|
||||
description = "Pull and rebuild ${site.name}";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = updateScript site;
|
||||
};
|
||||
}) sites)
|
||||
// {
|
||||
webhook-deploy = {
|
||||
description = "Webhook server for Pelican site rebuilds";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" "sops-nix.service" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
RuntimeDirectory = "webhook-deploy";
|
||||
ExecStartPre = "+${makeHooks}";
|
||||
ExecStart = "${pkgs.webhook}/bin/webhook -hooks /run/webhook-deploy/hooks.json -port 9000";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
mtproto_secret: ENC[AES256_GCM,data:MyzyUCH8cLOG+GMtmV03daJ9sqwOw/ozN2yi/14SMlY=,iv:LLf2LIvX+jNjRdMHclHpsmTZa7wmVM3gD6RbqeCGmik=,tag:i36lVESyKJafsn14kSzh3g==,type:str]
|
||||
codeberg_id_ed25519: ENC[AES256_GCM,data:AZbFWfc80HVskenEVLYL9MOYrGhW7Cwzdqv8gS4+1JGfk+nC801SmMgElUdISo+3m/O54b8RbJtdVz2u99gL8WG6wgbK7xqf40q4HNvV5cFXp7L/ozUkT41uXjWsDIdnMwumOqL/vjXowmAay30kMOiD5M4DL0t6EmuOo1Rcdffe/HwCVd2Pz7ZpU+BSTQV/pDTK1X3taUCjCY3Ui0XrcSCY8G2tuX5pFQ6t+vLrdqy3UGhofYHQ+nZuoyEKQHCcvEhYvEgDPJtyy+gk96vZCDYyXb9am/5k0I+MoIsArpavp4P0r5dNDcTnuCHH+fVPTG4tOsG/Ztf1rFBCsqPiM0azNElI8FERSKLYipuDDD8GI46p43OalHw4pxmAHXNOs70PfIH25iFJ5AUb32v2A71LScJMNP/TFSSezuq6g5eTd/JrtpQnWwToH1eVrwcN/8YX3xflLZ2JO1q4fjCXrkYHyw004dV/HAq3u1XQDmfMviZiH80+hiVIgZLfMWv5IyzfuomqSnfOj6oJ6D+j,iv:37HiX60OnO/zZFs1v4VWQLxcaoC1byZ3N2ueYFh4BVQ=,tag:5+z2YlnA8+MEcQTTrYhPJA==,type:str]
|
||||
webhook_secret: ENC[AES256_GCM,data:iLDVsnRCifIXdZzuTTDRT/XHQoW4O/C2Wc33cxn3QoiZNgVXJef50In8+mKPy6SXV05iJqe/0YdOXF3IsHbelA==,iv:Ve/jQx6xPeS3O5h67cideBpGEhJSCVgtDfIypQSmIMc=,tag:Lcp+buNI23SSXVW9Vsn1RQ==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1647c5f46njylggj33h26t6twhq57n5qeaza04l845uy0fksv0ucsq82c3d
|
||||
|
|
@ -11,7 +12,7 @@ sops:
|
|||
U0x1ZmtzLytSL1Y3cVo1ZVJ2Ymtob1EKTpgjSymQx14wLSuUhh5Txq++3DrLS4Bs
|
||||
x8vVtQgcXZgv1q0OMGup6DT4bkY6UiNbn9bAt4rHCaRPeb15x4ZKNw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-02-05T14:18:42Z"
|
||||
mac: ENC[AES256_GCM,data:sZTFVbWYhtYML6tZrivXYGm8ug+isUf7wi0VWwQ0Wx1Swany1RSkyQI7N0eFs58tVsY2KoizOShvLkC8UcpRvtog1M/OyZi0LypYkfMUD7Rth11AF2n3Tg4Q3VNH5DGcLWkzYleA4mj1mJnPyCQzKOykXSPocODAcKUyFYcP8uQ=,iv:ZxuNWYQesR6mtezi5yBRacPF4GC5NDsevaSlRJ+A6X4=,tag:htOCSco/V2/twoRRWeoBbA==,type:str]
|
||||
lastmodified: "2026-05-14T10:35:18Z"
|
||||
mac: ENC[AES256_GCM,data:aTYOA9JxUYYhlqN9Cgocxl50qiSvZ5wCVCgNf15yUNmxXhuaQW8FV1TNXBrJ++k6AQ7+Yerh6cDEu3wjXg38oNdVF60pU4xlMFsQZy337yUXIi0IwStuy7hwshDj6prnROg2a0s77MpSJQLPHF2yQpFv1pHW3aTC3HAiCXcKrL0=,iv:PYOYeHCa4IHE9Kx87ECyMNRtfgmaZ4QUg4rsvjiSgSI=,tag:dGBhf8RW/PRGbA6XziaSAQ==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.11.0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue