diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..439abc2 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,48 @@ +name: Build and Deploy +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: nix + steps: + - uses: https://github.com/actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build NixOS configuration + run: | + nix build .#nixosConfigurations.muffin.config.system.build.toplevel -L + + - name: Deploy via deploy-rs + run: | + eval $(ssh-agent -s) + ssh-add /run/agenix/ci-deploy-key + nix run github:serokell/deploy-rs -- .#muffin --ssh-opts="-o StrictHostKeyChecking=no" + + - name: Health check + run: | + sleep 10 + ssh -i /run/agenix/ci-deploy-key -o StrictHostKeyChecking=no root@server-public \ + "systemctl is-active gitea && systemctl is-active caddy && systemctl is-active continuwuity && systemctl is-active coturn" + + - name: Notify success + if: success() + run: | + curl -sf -X POST \ + "https://ntfy.sigkill.computer/deployments" \ + -H "Title: [muffin] Deploy succeeded" \ + -H "Priority: default" \ + -H "Tags: white_check_mark" \ + -d "server-config deployed from commit ${GITHUB_SHA::8}" + + - name: Notify failure + if: failure() + run: | + curl -sf -X POST \ + "https://ntfy.sigkill.computer/deployments" \ + -H "Title: [muffin] Deploy FAILED" \ + -H "Priority: urgent" \ + -H "Tags: rotating_light" \ + -d "server-config deploy failed at commit ${GITHUB_SHA::8}" diff --git a/configuration.nix b/configuration.nix index 9af329f..1a002e1 100644 --- a/configuration.nix +++ b/configuration.nix @@ -26,6 +26,7 @@ ./services/caddy.nix ./services/immich.nix ./services/gitea.nix + ./services/gitea-actions-runner.nix ./services/minecraft.nix ./services/wg.nix @@ -249,6 +250,14 @@ users.groups.${service_configs.media_group} = { }; + users.users.gitea-runner = { + isSystemUser = true; + group = "gitea-runner"; + home = "/var/lib/gitea-runner"; + description = "Gitea Actions CI runner"; + }; + users.groups.gitea-runner = { }; + users.users.${username} = { isNormalUser = true; extraGroups = [ diff --git a/modules/age-secrets.nix b/modules/age-secrets.nix index 81cb4be..6e527bf 100644 --- a/modules/age-secrets.nix +++ b/modules/age-secrets.nix @@ -128,5 +128,28 @@ group = "continuwuity"; }; + # CI deploy SSH key + ci-deploy-key = { + file = ../secrets/ci-deploy-key.age; + mode = "0400"; + owner = "gitea-runner"; + group = "gitea-runner"; + }; + + # Git-crypt symmetric key for dotfiles repo + git-crypt-key-dotfiles = { + file = ../secrets/git-crypt-key-dotfiles.age; + mode = "0400"; + owner = "gitea-runner"; + group = "gitea-runner"; + }; + + # Gitea Actions runner registration token + gitea-runner-token = { + file = ../secrets/gitea-runner-token.age; + mode = "0400"; + owner = "gitea-runner"; + group = "gitea-runner"; + }; }; } diff --git a/modules/impermanence.nix b/modules/impermanence.nix index 86d36f0..0eee73c 100644 --- a/modules/impermanence.nix +++ b/modules/impermanence.nix @@ -24,6 +24,7 @@ # ZFS cache directory - persisting the directory instead of the file # avoids "device busy" errors when ZFS atomically updates the cache "/etc/zfs" + "/var/lib/gitea-runner" ]; files = [ diff --git a/secrets/ci-deploy-key.age b/secrets/ci-deploy-key.age new file mode 100644 index 0000000..da1e327 Binary files /dev/null and b/secrets/ci-deploy-key.age differ diff --git a/secrets/git-crypt-key-dotfiles.age b/secrets/git-crypt-key-dotfiles.age new file mode 100644 index 0000000..1483fad Binary files /dev/null and b/secrets/git-crypt-key-dotfiles.age differ diff --git a/secrets/gitea-runner-token.age b/secrets/gitea-runner-token.age new file mode 100644 index 0000000..8f687a8 Binary files /dev/null and b/secrets/gitea-runner-token.age differ diff --git a/services/gitea-actions-runner.nix b/services/gitea-actions-runner.nix new file mode 100644 index 0000000..686063a --- /dev/null +++ b/services/gitea-actions-runner.nix @@ -0,0 +1,46 @@ +{ + config, + lib, + pkgs, + service_configs, + ... +}: +{ + services.gitea-actions-runner.instances.muffin = { + enable = true; + name = "muffin"; + url = config.services.gitea.settings.server.ROOT_URL; + tokenFile = config.age.secrets.gitea-runner-token.path; + labels = [ "nix:host" ]; + hostPackages = with pkgs; [ + bash + coreutils + curl + gawk + git + git-crypt + gnugrep + gnused + jq + nix + nodejs + openssh + ]; + settings = { + runner = { + capacity = 1; + timeout = "3h"; + }; + }; + }; + + # Override DynamicUser to use our static gitea-runner user + systemd.services."gitea-runner-muffin" = { + serviceConfig = { + DynamicUser = lib.mkForce false; + User = "gitea-runner"; + Group = "gitea-runner"; + }; + environment.GIT_SSH_COMMAND = "ssh -i /run/agenix/ci-deploy-key -o StrictHostKeyChecking=no"; + }; +} diff --git a/services/gitea.nix b/services/gitea.nix index dff1abe..907abe5 100644 --- a/services/gitea.nix +++ b/services/gitea.nix @@ -37,6 +37,7 @@ }; # only I shall use gitea service.DISABLE_REGISTRATION = true; + actions.ENABLED = true; }; }; diff --git a/services/ssh.nix b/services/ssh.nix index d5b0730..e0f2a4f 100644 --- a/services/ssh.nix +++ b/services/ssh.nix @@ -31,5 +31,8 @@ # used for deploying configs to server users.users.root.openssh.authorizedKeys.keys = - config.users.users.${username}.openssh.authorizedKeys.keys; + config.users.users.${username}.openssh.authorizedKeys.keys + ++ [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC5ZYN6idL/w/mUIfPOH1i+Q/SQXuzAMQUEuWpipx1Pc ci-deploy@muffin" + ]; }