feat(*): initialize new Snix infrastructure

Co-Authored-By: edef <edef@edef.eu>
Co-Authored-by: Ryan Lahfa <raito@lix.systems>
Change-Id: Ica1cda177a236814de900f50a8a61d288f58f519
This commit is contained in:
Florian Klink 2025-01-06 01:06:47 +01:00
parent 067eff3427
commit a52ea3675c
124 changed files with 27723 additions and 1631 deletions

305
ops/modules/forgejo.nix Normal file
View file

@ -0,0 +1,305 @@
#
# Forgejo Git Backend taken from Lix configuration.
# Thanks to all the Lix core developers for this!
# vim: et:ts=2:sw=2:
#
{ depot, pkgs, lib, config, ... }:
let
cfg = config.services.depot.forgejo;
inherit (lib) types mkEnableOption mkOption mkIf;
emojo =
let
handlePostFetch = ''
for i in $out/*_256.png; do
mv $i $(echo $i | sed -E 's/_256//g')
done
'';
drgn = pkgs.fetchzip {
url = "https://volpeon.ink/emojis/drgn/drgn.zip";
stripRoot = false;
sha256 = "sha256-/2MpbxMJC92a4YhwG5rP6TsDC/q1Ng5fFq4xe2cBrrM=";
postFetch = handlePostFetch;
};
neocat = pkgs.fetchzip {
url = "https://volpeon.ink/emojis/neocat/neocat.zip";
stripRoot = false;
sha256 = "sha256-Irh6Mv6ICDkaaenIFf8Cm1AFkdZy0gRVbXqgnwpk3Qw=";
postFetch = handlePostFetch;
};
neofox = pkgs.fetchzip {
url = "https://volpeon.ink/emojis/neofox/neofox.zip";
stripRoot = false;
sha256 = "sha256-FSTVYP/Bt25JfLr/Ny1g9oI9aAvAYLYhct31j3XRXYc=";
postFetch = handlePostFetch;
};
dragon = pkgs.fetchFromGitHub {
owner = "chr-1x";
repo = "dragn-emoji";
rev = "969543d9918ce2f0794ccd1e41b276d1ab22f0d5";
sha256 = "sha256-+40e9nKaIpQYZUiXh3Qe5jp2uvRbAQYDdXMGLEWHJio=";
postFetch = ''
for i in $out/*.svg; do
${pkgs.librsvg}/bin/rsvg-convert -h 256 $i > a.png;
mv a.png $(echo $i | sed -E "s/svg$/png/");
rm $i
done
${pkgs.oxipng}/bin/oxipng -o max $out/*.png
'';
};
in
pkgs.symlinkJoin { name = "emojo"; paths = [ drgn neocat neofox dragon ]; };
in
{
options.services.depot.forgejo = {
enable = mkEnableOption "Forgejo Forge";
domain = mkOption {
type = types.str;
};
};
config = mkIf cfg.enable {
# we have to use redis since we apparently have a "large instance" which
# "leaks hilarious amounts of memory if you use the default configuration"
services.redis = {
package = pkgs.valkey;
vmOverCommit = true;
servers.forgejo = {
enable = true;
# disable persistence, so when redis inevitably OOMs due to
# forgejo throwing to much in it, we don't restore the dataset
# that caused the OOM, breaking the restart loop.
save = [ ];
};
};
systemd.services.redis-forgejo.serviceConfig = {
Restart = "always";
};
systemd.services.forgejo = {
after = [ "redis-forgejo.service" ];
wants = [ "redis-forgejo.service" ];
};
services.forgejo = {
enable = true;
package = pkgs.forgejo.overrideAttrs (old: {
patches = old.patches ++ (with depot.third_party.lix_forgejo.patches; [
upstream_link
signin_redirect
api_dont_notify
forgejo_is_now_gerrit_native
forgejo_knows_about_gerrit
]);
});
# General settings.
lfs.enable = true;
# Make our checkout paths more in line with expectations by calling our user "git".
user = "git";
group = "git";
# Secret mail config.
# mailerPasswordFile = config.age.secrets.forgejoSmtpSecret.path;
# Server and database config.
settings = {
# Sets the name in the titlebar, mostly.
DEFAULT.APP_NAME = "Snix Project";
# Settings for how we serve things.
server = {
DOMAIN = cfg.domain;
PROTOCOL = "http";
ENABLE_ACME = true;
ACME_ACCEPTTOS = true;
ACME_EMAIL = "acme@snix.dev";
LANDING_PAGE = "explore";
ROOT_URL = "https://${cfg.domain}";
# open a server on localhost:6060 with pprof data
# !! note: the documentation says that this causes forgejo serv to dump
# random files in PPROF_DATA_PATH.
# This documentation is wrong, ENABLE_PPROF only affects forgejo web,
# and forgejo serv requires a --enable-pprof arg to do that. But it's
# not causing perf problems right now so we don't care about that
# anyway.
ENABLE_PPROF = true;
};
# openid is not used in our setup
openid = {
ENABLE_OPENID_SIGNIN = false;
ENABLE_OPENID_SIGNUP = false;
};
oauth2_client = {
ENABLE_AUTO_REGISTRATION = true;
REGISTER_EMAIL_CONFIRM = false;
ACCOUNT_LINKING = "login";
USERNAME = "nickname";
OPENID_CONNECT_SCOPES = "email profile";
};
cache = {
ADAPTER = "redis";
HOST = "redis+socket://${config.services.redis.servers.forgejo.unixSocket}";
};
"cache.last_commit" = {
ITEM_TTL = "24h"; # from default 8760h (1 year)
};
service = {
# We previously ran with "disable registration" which doesn't actually
# do anything to the OAuth login form, just the link account form. We
# suspect that if the account has all the required metadata like email
# to register cleanly, it doesn't use DISABLE_REGISTRATION at all.
#
# However this was probably relying on forgejo bugs, let's set it
# unambiguously.
DISABLE_REGISTRATION = false;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
#REQUIRE_SIGNIN_VIEW = false;
ENABLE_NOTIFY_MAIL = true;
# Don't add org members as watchers on all repos, or indeed on new
# repos either.
#
# See: https://github.com/bmackinney/gitea/commit/a9eb2167536cfa8f7b7a23f73e11c8edf5dc0dc0
AUTO_WATCH_NEW_REPOS = false;
};
session = {
# Put sessions in the DB so they survive restarts
PROVIDER = "db";
PROVIDER_CONFIG = "";
# Cookie only works over https
COOKIE_SECURE = true;
# 5 day sessions
SESSION_LIFE_TIME = 86400 * 5;
};
# Careful with these!
security = {
# Don't allow access to the install page; manage exclusively via Nix.
INSTALL_LOCK = true;
# Allow internal users with the right permissions to set up Git hooks.
DISABLE_GIT_HOOKS = false;
};
# Note: PASSWD is set by NixOS up.
# mailer = {
# ENABLED = true;
# PROTOCOL = "smtps";
# SMTP_ADDR = "";
# SMTP_PORT = 465;
# USER = "";
# FROM = "";
# };
ui = {
# Add the used emojis from https://volpeon.ink/emojis/ as well as https://github.com/chr-1x/dragn-emoji
CUSTOM_EMOJIS = builtins.readFile depot.third_party.lix_forgejo.custom_emojis;
# Normal reaction emoji people always need.
REACTIONS = "+1, -1, laugh, confused, heart, hooray, eyes, melting_face, neocat_scream_scared, neofox_scream_scared, drgn_scream, neocat_heart, neofox_heart, drgn_heart, neocat_floof_reach, neocat_pleading, neofox_floof_reach, neofox_pleading, drgn_pleading";
# To protect privacy of users.
SHOW_USER_EMAIL = false;
};
# No runners are configured.
actions.ENABLED = false;
};
# Use a MySQL database, which we enable below.
database = {
type = "mysql";
user = config.services.forgejo.user;
};
};
# Inspired from Gerrit's way of doing things (from Lix).
# Before starting Forgejo, we will re-converge any required information.
# TODO: learn how to use update-oauth as well?
systemd.services.forgejo-keys = {
enable = true;
before = [ "forgejo.service" ];
wantedBy = [ "forgejo.service" ];
after = [ "network.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "true";
WorkingDirectory = "/var/lib/forgejo";
User = "git";
Group = "git";
Environment = [
"FORGEJO_WORK_DIR=/var/lib/forgejo"
];
};
path = [ config.services.forgejo.package ];
script = ''
NAME="Snix project"
PROVIDER="openidConnect"
CLIENT_ID="forgejo"
CLIENT_SECRET=$(cat ${config.age.secrets.forgejo-oauth-secret.path})
DISCOVERY_URL="https://auth.snix.dev/realms/snix-project/.well-known/openid-configuration"
SCOPES=("openid" "profile" "email")
# Check if the OAuth2 source already exists
if gitea admin auth list | grep -q "$NAME"; then
echo "OAuth2 source '$NAME' already exists. Skipping creation."
exit 0
fi
# Add the OAuth2 source
gitea admin auth add-oauth \
--name "$NAME" \
--provider "$PROVIDER" \
--key "$CLIENT_ID" \
--secret "$CLIENT_SECRET" \
--auto-discover-url "$DISCOVERY_URL" \
$(printf -- '--scopes "%s" ' "''${SCOPES[@]}") \
--icon-url "$ICON_URL"
echo "OAuth2 source '$NAME' added successfully."
'';
};
# Create our user an group. This is necessary for any name that's
# not "forgejo", due to the nix module config.
users.users."${config.services.forgejo.group}" = {
description = "Gitea Service";
useDefaultShell = true;
home = config.services.forgejo.stateDir;
group = config.services.forgejo.group;
# redis instance runs as redis-forgejo, so we need to be in that group to be able to connect
extraGroups = [ "redis-forgejo" ];
isSystemUser = true;
};
users.groups."${config.services.forgejo.group}" = { };
# Enable the mysql server, which will provide the forgejo backing store.
services.mysql.enable = lib.mkForce true;
services.mysql.package = lib.mkForce pkgs.mariadb;
systemd.tmpfiles.rules = let cfg = config.services.forgejo; in [
"d '${cfg.customDir}/public/assets' 0750 ${cfg.user} ${cfg.group} - -"
"d '${cfg.customDir}/public/assets/img' 0750 ${cfg.user} ${cfg.group} - -"
"L+ '${cfg.customDir}/public/assets/img/emoji' - - - - ${emojo}"
];
};
}