Skip to content

Commit

Permalink
nixos/cgit: use isolated fcgiwrap instance, add user/group options
Browse files Browse the repository at this point in the history
This adds options to set the users and groups as which cgit instances
run, allowing the use of an unprivileged user instead of root.

"root" is kept as the default user to avoid breaking existing setups,
but a warning is shown in that case to alert the user.

Backport of:

commit 4f2da6c
    nixos/fcgiwrap: add option migration instruction errors
    (partial: move to instances)
commit 3d10deb
    nixos/cgit: fix GIT_PROJECT_ROOT ownership
commit 2d8626b
    nixos/cgit: configurable user instead of root
commit c5dc3e2
    nixos/fcgiwrap: adapt consumer modules and tests
commit 8101ae4
    nixos/fcgiwrap: adapt consumer modules and tests
commit bf2ad6f
    nixos/fcgiwrap: adapt consumer modules and tests
  • Loading branch information
pacien committed Aug 2, 2024
1 parent 483dd7e commit 31cdff5
Showing 1 changed file with 75 additions and 28 deletions.
103 changes: 75 additions & 28 deletions nixos/modules/services/networking/cgit.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ let

regexLocation = cfg: regexEscape (stripLocation cfg);

mkFastcgiPass = cfg: ''
mkFastcgiPass = name: cfg: ''
${if cfg.nginx.location == "/" then ''
fastcgi_param PATH_INFO $uri;
'' else ''
fastcgi_split_path_info ^(${regexLocation cfg})(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
''
}fastcgi_pass unix:${config.services.fcgiwrap.socketAddress};
}fastcgi_pass unix:${config.services.fcgiwrap.instances."cgit-${name}".socket.address};
'';

cgitrcLine = name: value: "${name}=${
Expand Down Expand Up @@ -72,25 +72,11 @@ let
${cfg.extraConfig}
'';

mkCgitReposDir = cfg:
if cfg.scanPath != null then
cfg.scanPath
else
pkgs.runCommand "cgit-repos" {
preferLocalBuild = true;
allowSubstitutes = false;
} ''
mkdir -p "$out"
${
concatStrings (
mapAttrsToList
(name: value: ''
ln -s ${escapeShellArg value.path} "$out"/${escapeShellArg name}
'')
cfg.repos
)
}
'';
fcgiwrapUnitName = name: "fcgiwrap-cgit-${name}";
fcgiwrapRuntimeDir = name: "/run/${fcgiwrapUnitName name}";
gitProjectRoot = name: cfg: if cfg.scanPath != null
then cfg.scanPath
else "${fcgiwrapRuntimeDir name}/repos";

in
{
Expand Down Expand Up @@ -154,6 +140,30 @@ in
type = types.lines;
default = "";
};

user = mkOption {
description = ''
User to run the cgit service as.
Defaults to "root" for compatibility with legacy setups.
Will default to the unprivileged user "cgit" in NixOS 24.11.
'';
type = types.str;
default = "root";
example = "cgit";
};

group = mkOption {
description = ''
Group to run the cgit service as.
Defaults to "root" for compatibility with legacy setups.
Will default to the unprivileged user "cgit" in NixOS 24.11.
'';
type = types.str;
default = "root";
example = "cgit";
};
};
}));
};
Expand All @@ -165,29 +175,66 @@ in
message = "Exactly one of services.cgit.${vhost}.scanPath or services.cgit.${vhost}.repos must be set.";
}) cfgs;

services.fcgiwrap.enable = true;
warnings = flatten (flip mapAttrsToList cfgs (inst: cfg:
optional (cfg.user == "root") ''
`services.cgit.${inst}` is configured to run as root.
This has security implications: <TODO: advisory link>.
It is recommended to set an unprivileged user explicitly.
This default user will be set to "cgit" in NixOS 24.11.
''
));

users = mkMerge (flip mapAttrsToList cfgs (_: cfg: {
users.${cfg.user} = {
isSystemUser = true;
inherit (cfg) group;
};
groups.${cfg.group} = { };
}));

services.fcgiwrap.instances = flip mapAttrs' cfgs (name: cfg:
nameValuePair "cgit-${name}" {
process = { inherit (cfg) user group; };
socket = { inherit (config.services.nginx) user group; };
}
);

systemd.services = flip mapAttrs' cfgs (name: cfg:
nameValuePair (fcgiwrapUnitName name)
(mkIf (cfg.repos != { }) {
serviceConfig.RuntimeDirectory = fcgiwrapUnitName name;
preStart = ''
GIT_PROJECT_ROOT=${escapeShellArg (gitProjectRoot name cfg)}
mkdir -p "$GIT_PROJECT_ROOT"
cd "$GIT_PROJECT_ROOT"
${concatLines (flip mapAttrsToList cfg.repos (name: repo: ''
ln -s ${escapeShellArg repo.path} ${escapeShellArg name}
''))}
'';
}
));

services.nginx.enable = true;

services.nginx.virtualHosts = mkMerge (mapAttrsToList (_: cfg: {
services.nginx.virtualHosts = mkMerge (mapAttrsToList (name: cfg: {
${cfg.nginx.virtualHost} = {
locations = (
genAttrs'
[ "cgit.css" "cgit.png" "favicon.ico" "robots.txt" ]
(name: nameValuePair "= ${stripLocation cfg}/${name}" {
(fileName: nameValuePair "= ${stripLocation cfg}/${fileName}" {
extraConfig = ''
alias ${cfg.package}/cgit/${name};
alias ${cfg.package}/cgit/${fileName};
'';
})
) // {
"~ ${regexLocation cfg}/.+/(info/refs|git-upload-pack)" = {
fastcgiParams = rec {
SCRIPT_FILENAME = "${pkgs.git}/libexec/git-core/git-http-backend";
GIT_HTTP_EXPORT_ALL = "1";
GIT_PROJECT_ROOT = mkCgitReposDir cfg;
GIT_PROJECT_ROOT = gitProjectRoot name cfg;
HOME = GIT_PROJECT_ROOT;
};
extraConfig = mkFastcgiPass cfg;
extraConfig = mkFastcgiPass name cfg;
};
"${stripLocation cfg}/" = {
fastcgiParams = {
Expand All @@ -196,7 +243,7 @@ in
HTTP_HOST = "$server_name";
CGIT_CONFIG = mkCgitrc cfg;
};
extraConfig = mkFastcgiPass cfg;
extraConfig = mkFastcgiPass name cfg;
};
};
};
Expand Down

0 comments on commit 31cdff5

Please sign in to comment.