krebs.git.rules: specify type

This commit is contained in:
tv 2016-02-03 13:36:54 +01:00
parent 68655d1ddf
commit cdb590be50
2 changed files with 142 additions and 55 deletions

View File

@ -44,48 +44,8 @@ let
default = "/etc/git"; default = "/etc/git";
}; };
repos = mkOption { repos = mkOption {
type = types.attrsOf (types.submodule ({ type = types.attrsOf subtypes.repo;
options = {
desc = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Repository description.
'';
};
section = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Repository section.
'';
};
name = mkOption {
type = types.str;
description = ''
Repository name.
'';
};
hooks = mkOption {
type = types.attrsOf types.str;
default = {};
description = ''
Repository-specific hooks.
'';
};
public = mkOption {
type = types.bool;
default = false;
description = ''
Allow everybody to read the repository via HTTP if cgit enabled.
'';
# TODO allow every configured user to fetch the repository via SSH.
};
};
}));
default = {}; default = {};
example = literalExample '' example = literalExample ''
{ {
testing = { testing = {
@ -99,7 +59,6 @@ let
testing2 = { name = "testing2"; }; testing2 = { name = "testing2"; };
} }
''; '';
description = '' description = ''
Repositories. Repositories.
''; '';
@ -121,28 +80,156 @@ let
''; '';
}; };
rules = mkOption { rules = mkOption {
type = types.unspecified; type = types.listOf subtypes.rule;
default = [];
example = literalExample ''
singleton {
user = [ config.krebs.users.tv ];
repo = [ testing ]; # see literal example of repos
perm = push "refs/*" (with lib.git; [
non-fast-forward create delete merge
]);
}
'';
description = ''
Rules.
'';
}; };
}; };
# TODO put into krebs/4lib/types.nix?
subtypes = {
repo = types.submodule ({
options = {
collaborators = mkOption {
type = types.listOf types.user;
default = [];
description = ''
List of users that should be able to fetch from this repo.
This option is currently not used by krebs.git but instead can be
used to create rules. See e.g. <stockholm/tv/2configs/git.nix> for
an example.
'';
};
desc = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Repository description.
'';
};
section = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Repository section.
'';
};
name = mkOption {
type = types.str;
description = ''
Repository name.
'';
};
hooks = mkOption {
type = types.attrsOf types.str;
default = {};
description = ''
Repository-specific hooks.
'';
};
public = mkOption {
type = types.bool;
default = false;
description = ''
Allow everybody to read the repository via HTTP if cgit enabled.
'';
# TODO allow every configured user to fetch the repository via SSH.
};
};
});
rule = types.submodule ({ config, ... }: {
options = {
user = mkOption {
type = types.listOf types.user;
description = ''
List of users this rule should apply to.
Checked by authorize-command.
'';
};
repo = mkOption {
type = types.listOf subtypes.repo;
description = ''
List of repos this rule should apply to.
Checked by authorize-command.
'';
};
perm = mkOption {
type = types.submodule {
# TODO generate enum argument from krebs/4lib/git.nix
options = {
allow-commands = mkOption {
type = types.listOf (types.enum (with git; [
git-receive-pack
git-upload-pack
]));
default = [];
description = ''
List of commands the rule's users are allowed to execute.
Checked by authorize-command.
'';
};
allow-receive-ref = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Ref that can receive objects.
Checked by authorize-push.
'';
};
allow-receive-modes = mkOption {
type = types.listOf (types.enum (with git; [
fast-forward
non-fast-forward
create
delete
merge
]));
default = [];
description = ''
List of allowed receive modes.
Checked by pre-receive hook.
'';
};
};
};
description = ''
Permissions granted.
'';
};
};
});
};
git-imp = { git-imp = {
system.activationScripts.git-init = "${init-script}"; system.activationScripts.git-init = "${init-script}";
# TODO maybe put all scripts here and then use PATH? # TODO maybe put all scripts here and then use PATH?
environment.etc."${etc-base}".source = environment.etc."${etc-base}".source =
scriptFarm "git-ssh-authorizers" { scriptFarm "git-ssh-authorizers" {
authorize-command = makeAuthorizeScript (map ({ repo, user, perm }: [ authorize-command = makeAuthorizeScript (map (rule: [
(map getName (ensureList user)) (map getName (ensureList rule.user))
(map getName (ensureList repo)) (map getName (ensureList rule.repo))
(map getName perm.allow-commands) (map getName rule.perm.allow-commands)
]) cfg.rules); ]) cfg.rules);
authorize-push = makeAuthorizeScript (map ({ repo, user, perm }: [ authorize-push = makeAuthorizeScript (map (rule: [
(map getName (ensureList user)) (map getName (ensureList rule.user))
(map getName (ensureList repo)) (map getName (ensureList rule.repo))
(ensureList perm.allow-receive-ref) (ensureList rule.perm.allow-receive-ref)
(map getName perm.allow-receive-modes) (map getName rule.perm.allow-receive-modes)
]) (filter (x: hasAttr "allow-receive-ref" x.perm) cfg.rules)); ]) (filter (rule: rule.perm.allow-receive-ref != null) cfg.rules));
}; };
users.extraUsers = singleton rec { users.extraUsers = singleton rec {

View File

@ -9,7 +9,7 @@ let
enable = true; enable = true;
root-title = "public repositories at ${config.krebs.build.host.name}"; root-title = "public repositories at ${config.krebs.build.host.name}";
root-desc = "keep calm and engage"; root-desc = "keep calm and engage";
repos = mapAttrs (_: s: removeAttrs s ["collaborators"]) repos; repos = repos;
rules = rules; rules = rules;
}; };
}; };
@ -99,7 +99,7 @@ let
repo = [ repo ]; repo = [ repo ];
perm = fetch; perm = fetch;
} ++ } ++
optional (length (repo.collaborators or []) > 0) { optional (repo.collaborators or [] != []) {
user = repo.collaborators; user = repo.collaborators;
repo = [ repo ]; repo = [ repo ];
perm = fetch; perm = fetch;