-
-
Notifications
You must be signed in to change notification settings - Fork 14.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sourcehut: include module #65109
sourcehut: include module #65109
Changes from all commits
a22657c
0dfe29f
469d040
6783593
262b8d0
6c61706
6dd2765
b015be3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
{ config, pkgs, lib, ... }: | ||
|
||
with lib; | ||
|
||
let | ||
cfg = config.services.sourcehut; | ||
cfgIni = cfg.settings; | ||
|
||
# Specialized python containing all the modules | ||
python = pkgs.sourcehut.python.withPackages (ps: with ps; [ | ||
gunicorn | ||
# Sourcehut services | ||
buildsrht dispatchsrht gitsrht hgsrht listssrht mansrht | ||
metasrht pastesrht todosrht | ||
]); | ||
in { | ||
imports = | ||
[ | ||
./git.nix | ||
./hg.nix | ||
./todo.nix | ||
./man.nix | ||
./meta.nix | ||
./paste.nix | ||
]; | ||
|
||
options.services.sourcehut = { | ||
enable = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Enable sourcehut - git hosting, continuous integration, mailing list, ticket tracking, | ||
task dispatching, wiki and account management services. | ||
''; | ||
}; | ||
|
||
services = mkOption { | ||
type = types.nonEmptyListOf (types.enum [ "builds" "dispatch" "git" "hg" "lists" "man" "meta" "paste" "todo" ]); | ||
default = [ "builds" "dispatch" "git" "hg" "lists" "man" "meta" "paste" "todo" ]; | ||
description = '' | ||
Services to enable on the sourcehut network. | ||
''; | ||
}; | ||
|
||
address = mkOption { | ||
type = types.str; | ||
default = "127.0.0.1"; | ||
description = '' | ||
''; | ||
}; | ||
|
||
python = mkOption { | ||
internal = true; | ||
type = types.package; | ||
default = python; | ||
description = '' | ||
The python package to use. It should contain references to the *srht modules and also | ||
gunicorn. | ||
''; | ||
}; | ||
|
||
statePath = mkOption { | ||
type = types.path; | ||
default = "/var/sourcehut"; | ||
description = '' | ||
Root state path for the sourcehut network. | ||
''; | ||
}; | ||
|
||
settings = mkOption { | ||
type = with types; attrsOf (attrsOf (nullOr (either bool (either int (either float (either str path)))))); | ||
default = {}; | ||
description = '' | ||
The configuration for the sourcehut network. | ||
''; | ||
}; | ||
}; | ||
|
||
config = mkIf cfg.enable { | ||
assertions = | ||
[ | ||
{ assertion = with cfgIni."sr.ht"; secret-key != null && stringLength secret-key == 32; | ||
message = "sr.ht's secret key must be defined and of a 32 byte length."; } | ||
|
||
# Is it always 44 characters...? At least from the times I've generated one... | ||
{ assertion = with cfgIni.webhooks; private-key != null && stringLength private-key == 44; | ||
message = "The webhook's private key must be defined."; } | ||
|
||
{ assertion = hasAttrByPath [ "meta.sr.ht" "origin" ] cfgIni && cfgIni."meta.sr.ht".origin != null; | ||
message = "meta.sr.ht's origin must be defined."; } | ||
]; | ||
|
||
environment.etc."sr.ht/config.ini".text = let | ||
mkKeyValue = key: v: let | ||
isPath = v: builtins.typeOf v == "path"; | ||
|
||
value = | ||
if null == v then "" | ||
else if true == v then "yes" | ||
else if false == v then "no" | ||
else if isInt v then toString v | ||
else if isString v then toString v | ||
else if isPath v then toString v | ||
else abort "sourcehut.mkKeyValue: unexpected type (v = ${v})"; | ||
in "${toString key}=${value}"; | ||
in generators.toINI { inherit mkKeyValue; } cfg.settings; | ||
|
||
environment.systemPackages = [ python ]; | ||
|
||
# PostgreSQL server | ||
services.postgresql.enable = true; | ||
# Mail server | ||
services.postfix.enable = mkOverride 999 true; | ||
# Cron daemon | ||
services.cron.enable = mkOverride 999 true; | ||
# Redis server | ||
services.redis = { | ||
enable = true; | ||
port = mkDefault 6379; | ||
# TODO: localhost | ||
bind = mkDefault "127.0.0.1"; | ||
# TODO: More like 2? | ||
databases = mkDefault 8; | ||
}; | ||
|
||
services.sourcehut.settings = { | ||
# The name of your network of sr.ht-based sites | ||
"sr.ht".site-name = mkDefault "sourcehut"; | ||
# The top-level info page for your site | ||
"sr.ht".site-info = mkDefault "https://sourcehut.org"; | ||
# {{ site-name }}, {{ site-blurb }} | ||
"sr.ht".site-blurb = mkDefault "the hacker's forge"; | ||
# If this != production, we add a banner to each page | ||
"sr.ht".environment = mkDefault "development"; | ||
# Contact information for the site owners | ||
"sr.ht".owner-name = mkDefault "Drew DeVault"; | ||
"sr.ht".owner-email = mkDefault "sir@cmpwn.com"; | ||
# The source code for your fork of sr.ht | ||
"sr.ht".source-url = mkDefault "https://git.sr.ht/~sircmpwn/srht"; | ||
# A secret key to encrypt session cookies with | ||
"sr.ht".secret-key = mkDefault null; | ||
|
||
# Outgoing SMTP settings | ||
mail.smtp-host = mkDefault null; | ||
mail.smtp-port = mkDefault null; | ||
mail.smtp-user = mkDefault null; | ||
mail.smtp-password = mkDefault null; | ||
mail.smtp-from = mkDefault null; | ||
# Application exceptions are emailed to this address | ||
mail.error-to = mkDefault null; | ||
mail.error-from = mkDefault null; | ||
# Your PGP key information (DO NOT mix up pub and priv here) | ||
# You must remove the password from your secret key, if present. | ||
# You can do this with gpg --edit-key [key-id], then use the passwd | ||
# command and do not enter a new password. | ||
mail.pgp-privkey = mkDefault null; | ||
mail.pgp-pubkey = mkDefault null; | ||
mail.pgp-key-id = mkDefault null; | ||
|
||
# base64-encoded Ed25519 key for signing webhook payloads. This should be | ||
# consistent for all *.sr.ht sites, as we'll use this key to verify signatures | ||
# from other sites in your network. | ||
# | ||
# Use the srht-webhook-keygen command to generate a key. | ||
webhooks.private-key = mkDefault null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Serious security problem here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIRC services e.g. ssh generate keys on service start if they're not present... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Appending won't fix the problem, it'll still end up in the store. If you don't want it to be in the store, the only option is to have as an external file and you're better off setting it up yourself since I can't access the settings unless I parse the file's contents. I'm pretty sure the generated key isn't suppose to be used for ssh connections. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why wont appending fix the problem? I dont think you understood what I meant. The file we're appending from is not in the store, and neiter is the file were appending to. Only the 'base' file (the one created here, without private keys) would be in the store. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I know, the only configuration file for sourcehut lies in
Would have the file contents of path_to_external_file in the file in the store. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This really is a sourcehut bug. Secrets dont go in config files. |
||
}; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
{ config, lib, pkgs, ... }: | ||
|
||
with lib; | ||
|
||
let | ||
cfg = config.services.sourcehut; | ||
scfg = cfg.git; | ||
iniKey = "git.sr.ht"; | ||
|
||
rcfg = config.services.redis; | ||
drv = pkgs.sourcehut.gitsrht; | ||
in { | ||
options.services.sourcehut.git = { | ||
user = mkOption { | ||
type = types.str; | ||
visible = false; | ||
internal = true; | ||
readOnly = true; | ||
default = "git"; | ||
description = '' | ||
User for git.sr.ht. | ||
''; | ||
}; | ||
|
||
port = mkOption { | ||
type = types.int; | ||
default = 5001; | ||
description = '' | ||
''; | ||
}; | ||
|
||
database = mkOption { | ||
type = types.str; | ||
default = "git.sr.ht"; | ||
description = '' | ||
PostgreSQL database name for git.sr.ht. | ||
''; | ||
}; | ||
|
||
statePath = mkOption { | ||
type = types.path; | ||
default = "${cfg.statePath}/gitsrht"; | ||
description = '' | ||
State path for git.sr.ht. | ||
''; | ||
}; | ||
}; | ||
|
||
config = with scfg; lib.mkIf (cfg.enable && elem "git" cfg.services) { | ||
# sshd refuses to run with `Unsafe AuthorizedKeysCommand ... bad ownership or modes for directory /nix/store` | ||
environment.etc."ssh/gitsrht-dispatch" = { | ||
mode = "0755"; | ||
text = '' | ||
#! ${pkgs.stdenv.shell} | ||
${cfg.python}/bin/gitsrht-dispatch $@ | ||
''; | ||
}; | ||
|
||
# Needs this in the $PATH when sshing into the server | ||
environment.systemPackages = [ pkgs.git ]; | ||
|
||
users = { | ||
users = [ | ||
{ name = user; | ||
group = user; | ||
# https://stackoverflow.com/questions/22314298/git-push-results-in-fatal-protocol-error-bad-line-length-character-this | ||
# Probably could use gitsrht-shell if output is restricted to just parameters... | ||
shell = "${pkgs.bash}/bin/bash"; | ||
description = "git.sr.ht user"; } | ||
]; | ||
|
||
groups = [ | ||
{ name = user; } | ||
]; | ||
}; | ||
|
||
services = { | ||
cron.systemCronJobs = [ "*/20 * * * * ${cfg.python}/bin/gitsrht-periodic" ]; | ||
fcgiwrap.enable = true; | ||
|
||
openssh.extraConfig = '' | ||
AuthorizedKeysCommand /etc/ssh/gitsrht-dispatch "%u" "%h" "%t" "%k" | ||
AuthorizedKeysCommandUser root | ||
PermitUserEnvironment SRHT_* | ||
''; | ||
|
||
postgresql = { | ||
authentication = '' | ||
local ${database} ${user} trust | ||
''; | ||
ensureDatabases = [ database ]; | ||
ensureUsers = [ | ||
{ name = user; | ||
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; }; } | ||
]; | ||
}; | ||
}; | ||
|
||
systemd = { | ||
tmpfiles.rules = [ | ||
# /var/log is owned by root | ||
"f /var/log/git-srht-shell 0644 ${user} ${user} -" | ||
|
||
"d ${statePath} 0750 ${user} ${user} -" | ||
"d ${cfg.settings."${iniKey}".repos} 2755 ${user} ${user} -" | ||
]; | ||
|
||
services = { | ||
gitsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey { | ||
after = [ "redis.service" "postgresql.service" "network.target" ]; | ||
requires = [ "redis.service" "postgresql.service" ]; | ||
wantedBy = [ "multi-user.target" ]; | ||
|
||
# Needs internally to create repos at the very least | ||
path = [ pkgs.git ]; | ||
description = "git.sr.ht website service"; | ||
|
||
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}"; | ||
}; | ||
|
||
gitsrht-webhooks = { | ||
after = [ "postgresql.service" "network.target" ]; | ||
requires = [ "postgresql.service" ]; | ||
wantedBy = [ "multi-user.target" ]; | ||
|
||
description = "git.sr.ht webhooks service"; | ||
serviceConfig = { | ||
Type = "simple"; | ||
User = user; | ||
Restart = "always"; | ||
}; | ||
|
||
serviceConfig.ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info"; | ||
}; | ||
}; | ||
}; | ||
|
||
services.sourcehut.settings = { | ||
# URL git.sr.ht is being served at (protocol://domain) | ||
"git.sr.ht".origin = mkDefault "http://git.sr.ht.local"; | ||
# Address and port to bind the debug server to | ||
"git.sr.ht".debug-host = mkDefault "0.0.0.0"; | ||
"git.sr.ht".debug-port = mkDefault port; | ||
# Configures the SQLAlchemy connection string for the database. | ||
"git.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql"; | ||
# Set to "yes" to automatically run migrations on package upgrade. | ||
"git.sr.ht".migrate-on-upgrade = mkDefault "yes"; | ||
# The redis connection used for the webhooks worker | ||
"git.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/1"; | ||
# A post-update script which is installed in every git repo. | ||
"git.sr.ht".post-update-script = mkDefault "${cfg.python}/bin/gitsrht-update-hook"; | ||
# git.sr.ht's OAuth client ID and secret for meta.sr.ht | ||
# Register your client at meta.example.org/oauth | ||
"git.sr.ht".oauth-client-id = mkDefault null; | ||
"git.sr.ht".oauth-client-secret = mkDefault null; | ||
# Path to git repositories on disk | ||
"git.sr.ht".repos = mkDefault "/var/lib/git"; | ||
|
||
# The authorized keys hook uses this to dispatch to various handlers | ||
# The format is a program to exec into as the key, and the user to match as the | ||
# value. When someone tries to log in as this user, this program is executed | ||
# and is expected to omit an AuthorizedKeys file. | ||
# | ||
# Uncomment the relevant lines to enable the various sr.ht dispatchers. | ||
"git.sr.ht::dispatch"."/run/current-system/sw/bin/gitsrht-keys" = mkDefault "${user}:${user}"; | ||
}; | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will produce a crazy type like the one in #86402. Can you add a decription with
// { description = "..."; }
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't there already a description for this in line 73?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think he meant an example maybe?