252 lines
7.7 KiB
Nix
252 lines
7.7 KiB
Nix
/*
|
|
This file has code copied from NixOS nixpkgs's repostiory, and can be located at
|
|
<https://github.com/NixOS/nixpkgs/blob/nixos-25.05/nixos/modules/services/misc/gitea.nix>
|
|
|
|
The original code is licensed under the MIT License (SPDX-License-Identifier: MIT),
|
|
which a copy of the copyright notice and license can be found at
|
|
<https://github.com/NixOS/nixpkgs/blob/nixos-25.05/COPYING> and below:
|
|
|
|
Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
with lib; let
|
|
cfg = config.services.gitea;
|
|
|
|
exe = getExe cfg.package;
|
|
format = pkgs.formats.ini {};
|
|
|
|
secrets = let
|
|
mkSecret = section: values:
|
|
mapAttrsToList (k: v: {
|
|
env = envEscape "GITEA__${section}__${k}__FILE";
|
|
path = v;
|
|
})
|
|
values;
|
|
envEscape = str: replaceStrings ["." "-"] ["_0X2E_" "_0X2D_"] (strings.toUpper str);
|
|
in
|
|
flatten (mapAttrsToList mkSecret cfg.secrets);
|
|
in {
|
|
options.services.gitea = {
|
|
secrets = mkOption {
|
|
default = {};
|
|
description = ''
|
|
This is a small wrapper over systemd's `LoadCredential`.
|
|
|
|
It takes the same sections and keys as {option}`services.forgejo.settings`,
|
|
but the value of each key is a path instead of a string or bool.
|
|
|
|
The path is then loaded as credential, exported as environment variable
|
|
and then feed through
|
|
<https://github.com/go-gitea/gitea/blob/v1.24.6/contrib/environment-to-ini/environment-to-ini.go>
|
|
|
|
It does the required environment variable escaping for you.
|
|
|
|
::: {.note}
|
|
Keys specified here take priority over the ones in {option}`services.forgejo.settings`!
|
|
:::
|
|
'';
|
|
example = literalExpression ''
|
|
{
|
|
metrics = {
|
|
TOKEN = "/run/keys/gitea-metrics-token";
|
|
};
|
|
camo = {
|
|
HMAC_KEY = "/run/keys/gitea-camo-hmac";
|
|
};
|
|
service = {
|
|
HCAPTCHA_SECRET = "/run/keys/gitea-hcaptcha-secret";
|
|
HCAPTCHA_SITEKEY = "/run/keys/gitea-hcaptcha-sitekey";
|
|
};
|
|
}
|
|
'';
|
|
type = with types;
|
|
submodule {
|
|
freeformType = attrsOf (attrsOf path);
|
|
options = {};
|
|
};
|
|
};
|
|
};
|
|
config = mkIf cfg.enable {
|
|
services.gitea.settings = {
|
|
DEFAULT = {
|
|
RUN_MODE = mkDefault "prod";
|
|
RUN_USER = mkDefault cfg.user;
|
|
WORK_PATH = mkDefault cfg.stateDir;
|
|
};
|
|
|
|
database = mkMerge [
|
|
{
|
|
DB_TYPE = cfg.database.type;
|
|
}
|
|
(mkIf (cfg.database.type == "postgres" || cfg.database.type == "mysql") {
|
|
HOST =
|
|
if cfg.database.socket != null
|
|
then cfg.database.socket
|
|
else cfg.database.host + ":" + toString cfg.database.port;
|
|
NAME = cfg.database.name;
|
|
USER = cfg.database.user;
|
|
})
|
|
(mkIf (cfg.database.type == "sqlite3") {
|
|
PATH = cfg.database.path;
|
|
})
|
|
(mkIf (cfg.database.type == "postgres") {
|
|
SSL_MODE = "disable";
|
|
})
|
|
];
|
|
|
|
repository = {
|
|
ROOT = cfg.repositoryRoot;
|
|
};
|
|
|
|
server = mkIf cfg.lfs.enable {
|
|
LFS_START_SERVER = true;
|
|
};
|
|
|
|
session = {
|
|
COOKIE_NAME = mkDefault "session";
|
|
};
|
|
|
|
security = {
|
|
INSTALL_LOCK = true;
|
|
};
|
|
|
|
lfs = mkIf cfg.lfs.enable {
|
|
PATH = cfg.lfs.contentDir;
|
|
};
|
|
};
|
|
|
|
services.gitea.secrets = {
|
|
security = {
|
|
SECRET_KEY = mkDefault "${cfg.customDir}/conf/secret_key";
|
|
INTERNAL_TOKEN = mkDefault "${cfg.customDir}/conf/internal_token";
|
|
};
|
|
|
|
oauth2 = {
|
|
JWT_SECRET = mkDefault "${cfg.customDir}/conf/oauth2_jwt_secret";
|
|
};
|
|
|
|
database = mkIf (cfg.database.passwordFile != null) {
|
|
PASSWD = cfg.database.passwordFile;
|
|
};
|
|
|
|
server = mkIf cfg.lfs.enable {
|
|
LFS_JWT_SECRET = mkDefault "${cfg.customDir}/conf/lfs_jwt_secret";
|
|
};
|
|
};
|
|
|
|
systemd.services.gitea-secrets = {
|
|
description = "Gitea secret bootstrap helper";
|
|
script = ''
|
|
if [ ! -s '${cfg.secrets.security.SECRET_KEY}' ]; then
|
|
${exe} generate secret SECRET_KEY > '${cfg.secrets.security.SECRET_KEY}'
|
|
fi
|
|
|
|
if [ ! -s '${cfg.secrets.oauth2.JWT_SECRET}' ]; then
|
|
${exe} generate secret JWT_SECRET > '${cfg.secrets.oauth2.JWT_SECRET}'
|
|
fi
|
|
|
|
${optionalString cfg.lfs.enable ''
|
|
if [ ! -s '${cfg.secrets.server.LFS_JWT_SECRET}' ]; then
|
|
${exe} generate secret LFS_JWT_SECRET > '${cfg.secrets.server.LFS_JWT_SECRET}'
|
|
fi
|
|
''}
|
|
|
|
if [ ! -s '${cfg.secrets.security.INTERNAL_TOKEN}' ]; then
|
|
${exe} generate secret INTERNAL_TOKEN > '${cfg.secrets.security.INTERNAL_TOKEN}'
|
|
fi
|
|
'';
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
User = cfg.user;
|
|
Group = cfg.group;
|
|
ReadWritePaths = [cfg.customDir];
|
|
UMask = "0077";
|
|
};
|
|
};
|
|
|
|
systemd.services.gitea = {
|
|
after =
|
|
[
|
|
"network.target"
|
|
]
|
|
++ optionals (cfg.database.type == "postgres") [
|
|
"postgresql.service"
|
|
]
|
|
++ optionals (cfg.database.type == "mysql") [
|
|
"mysql.service"
|
|
]
|
|
++ [
|
|
"gitea-secrets.service"
|
|
];
|
|
requires =
|
|
optionals (cfg.database.createDatabase && cfg.database.type == "postgres") [
|
|
"postgresql.service"
|
|
]
|
|
++ optionals (cfg.database.createDatabase && cfg.database.type == "mysql") [
|
|
"mysql.service"
|
|
]
|
|
++ [
|
|
"gitea-secrets.service"
|
|
];
|
|
|
|
# Copied from, to add secrets handling
|
|
# https://github.com/NixOS/nixpkgs/blob/20c4598c84a671783f741e02bf05cbfaf4907cff/nixos/modules/services/misc/forgejo.nix#L696
|
|
preStart = ''
|
|
# copy custom configuration and generate random secrets if needed
|
|
${''
|
|
function gitea_setup {
|
|
config='${cfg.customDir}/conf/app.ini'
|
|
cp -f '${format.generate "app.ini" cfg.settings}' "$config"
|
|
|
|
chmod u+w "$config"
|
|
${getExe' cfg.package "environment-to-ini"} --config "$config"
|
|
chmod u-w "$config"
|
|
}
|
|
(umask 027; gitea_setup)
|
|
''}
|
|
|
|
# run migrations/init the database
|
|
${exe} migrate
|
|
|
|
# update all hooks' binary paths
|
|
${exe} admin regenerate hooks
|
|
|
|
# update command option in authorized_keys
|
|
if [ -r ${cfg.stateDir}/.ssh/authorized_keys ]
|
|
then
|
|
${exe} admin regenerate keys
|
|
fi
|
|
'';
|
|
|
|
serviceConfig.LoadCredential = map (e: "${e.env}:${e.path}") secrets;
|
|
|
|
environment = listToAttrs (map (e: nameValuePair e.env "%d/${e.env}") secrets);
|
|
};
|
|
};
|
|
}
|