Project import generated by Copybara.
GitOrigin-RevId: 5b091d4fbe3b7b7493c3b46fe0842e4b30ea24b3
This commit is contained in:
parent
6cb1af2f35
commit
a425ba4985
515 changed files with 9997 additions and 6755 deletions
|
@ -764,7 +764,7 @@ and in this case the `python38` interpreter is automatically used.
|
||||||
|
|
||||||
### Interpreters {#interpreters}
|
### Interpreters {#interpreters}
|
||||||
|
|
||||||
Versions 2.7, 3.6, 3.7, 3.8 and 3.9 of the CPython interpreter are available as
|
Versions 2.7, 3.7, 3.8 and 3.9 of the CPython interpreter are available as
|
||||||
respectively `python27`, `python37`, `python38` and `python39`. The
|
respectively `python27`, `python37`, `python38` and `python39`. The
|
||||||
aliases `python2` and `python3` correspond to respectively `python27` and
|
aliases `python2` and `python3` correspond to respectively `python27` and
|
||||||
`python39`. The attribute `python` maps to `python2`. The PyPy interpreters
|
`python39`. The attribute `python` maps to `python2`. The PyPy interpreters
|
||||||
|
|
|
@ -1696,6 +1696,12 @@
|
||||||
fingerprint = "BF4FCB85C69989B4ED95BF938AE74787A4B7C07E";
|
fingerprint = "BF4FCB85C69989B4ED95BF938AE74787A4B7C07E";
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
broke = {
|
||||||
|
email = "broke@in-fucking.space";
|
||||||
|
github = "broke";
|
||||||
|
githubId = 1071610;
|
||||||
|
name = "Gunnar Nitsche";
|
||||||
|
};
|
||||||
bryanasdev000 = {
|
bryanasdev000 = {
|
||||||
email = "bryanasdev000@gmail.com";
|
email = "bryanasdev000@gmail.com";
|
||||||
matrix = "@bryanasdev000:matrix.org";
|
matrix = "@bryanasdev000:matrix.org";
|
||||||
|
@ -2134,6 +2140,12 @@
|
||||||
githubId = 3956062;
|
githubId = 3956062;
|
||||||
name = "Simon Lackerbauer";
|
name = "Simon Lackerbauer";
|
||||||
};
|
};
|
||||||
|
cirno-999 = {
|
||||||
|
email = "reverene@protonmail.com";
|
||||||
|
github = "cirno-999";
|
||||||
|
githubId = 73712874;
|
||||||
|
name = "cirno-999";
|
||||||
|
};
|
||||||
citadelcore = {
|
citadelcore = {
|
||||||
email = "alex@arctarus.co.uk";
|
email = "alex@arctarus.co.uk";
|
||||||
github = "citadelcore";
|
github = "citadelcore";
|
||||||
|
@ -3389,6 +3401,12 @@
|
||||||
githubId = 103082;
|
githubId = 103082;
|
||||||
name = "Ed Brindley";
|
name = "Ed Brindley";
|
||||||
};
|
};
|
||||||
|
elliot = {
|
||||||
|
email = "hack00mind@gmail.com";
|
||||||
|
github = "Eliot00";
|
||||||
|
githubId = 18375468;
|
||||||
|
name = "Elliot Xu";
|
||||||
|
};
|
||||||
elliottvillars = {
|
elliottvillars = {
|
||||||
email = "elliottvillars@gmail.com";
|
email = "elliottvillars@gmail.com";
|
||||||
github = "elliottvillars";
|
github = "elliottvillars";
|
||||||
|
@ -7066,6 +7084,12 @@
|
||||||
fingerprint = "BA3A 5886 AE6D 526E 20B4 57D6 6A37 DF94 8318 8492";
|
fingerprint = "BA3A 5886 AE6D 526E 20B4 57D6 6A37 DF94 8318 8492";
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
lux = {
|
||||||
|
email = "lux@lux.name";
|
||||||
|
githubId = 1208273;
|
||||||
|
matrix = "@lux:ontheblueplanet.com";
|
||||||
|
name = "Lux";
|
||||||
|
};
|
||||||
luz = {
|
luz = {
|
||||||
email = "luz666@daum.net";
|
email = "luz666@daum.net";
|
||||||
github = "Luz";
|
github = "Luz";
|
||||||
|
|
|
@ -14,7 +14,17 @@
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
<section xml:id="sec-release-22.05-highlights">
|
<section xml:id="sec-release-22.05-highlights">
|
||||||
<title>Highlights</title>
|
<title>Highlights</title>
|
||||||
<itemizedlist spacing="compact">
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>security.acme.defaults</literal> has been added to
|
||||||
|
simplify configuring settings for many certificates at once.
|
||||||
|
This also opens up the the option to use DNS-01 validation
|
||||||
|
when using <literal>enableACME</literal> on web server virtual
|
||||||
|
hosts (e.g.
|
||||||
|
<literal>services.nginx.virtualHosts.*.enableACME</literal>).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
PHP 8.1 is now available
|
PHP 8.1 is now available
|
||||||
|
@ -33,6 +43,14 @@
|
||||||
<link linkend="opt-services.aesmd.enable">services.aesmd</link>.
|
<link linkend="opt-services.aesmd.enable">services.aesmd</link>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<link xlink:href="https://docs.docker.com/engine/security/rootless/">rootless
|
||||||
|
Docker</link>, a <literal>systemd --user</literal> Docker
|
||||||
|
service which runs without root permissions. Available as
|
||||||
|
<link xlink:href="options.html#opt-virtualisation.docker.rootless.enable">virtualisation.docker.rootless.enable</link>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<link xlink:href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html">filebeat</link>,
|
<link xlink:href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html">filebeat</link>,
|
||||||
|
@ -85,6 +103,12 @@
|
||||||
new versions will release.
|
new versions will release.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>services.kubernetes.addons.dashboard</literal> was
|
||||||
|
removed due to it being an outdated version.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The <literal>wafHook</literal> hook now honors
|
The <literal>wafHook</literal> hook now honors
|
||||||
|
@ -122,6 +146,29 @@
|
||||||
<literal>virtualisation.docker.daemon.settings</literal>.
|
<literal>virtualisation.docker.daemon.settings</literal>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>autorestic</literal> package has been upgraded
|
||||||
|
from 1.3.0 to 1.5.0 which introduces breaking changes in
|
||||||
|
config file, check
|
||||||
|
<link xlink:href="https://autorestic.vercel.app/migration/1.4_1.5">their
|
||||||
|
migration guide</link> for more details.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
For <literal>pkgs.python3.pkgs.ipython</literal>, its direct
|
||||||
|
dependency
|
||||||
|
<literal>pkgs.python3.pkgs.matplotlib-inline</literal> (which
|
||||||
|
is really an adapter to integrate matplotlib in ipython if it
|
||||||
|
is installed) does not depend on
|
||||||
|
<literal>pkgs.python3.pkgs.matplotlib</literal> anymore. This
|
||||||
|
is closer to a non-Nix install of ipython. This has the added
|
||||||
|
benefit to reduce the closure size of
|
||||||
|
<literal>ipython</literal> from ~400MB to ~160MB (including
|
||||||
|
~100MB for python itself).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
<section xml:id="sec-release-22.05-notable-changes">
|
<section xml:id="sec-release-22.05-notable-changes">
|
||||||
|
@ -180,6 +227,20 @@
|
||||||
using this default will print a warning when rebuilt.
|
using this default will print a warning when rebuilt.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>security.acme</literal> certificates will now
|
||||||
|
correctly check for CA revokation before reaching their
|
||||||
|
minimum age.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Removing domains from
|
||||||
|
<literal>security.acme.certs._name_.extraDomainNames</literal>
|
||||||
|
will now correctly remove those domains during rebuild/renew.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The option
|
The option
|
||||||
|
@ -198,6 +259,13 @@
|
||||||
configuration.
|
configuration.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The option <literal>services.duplicati.dataDir</literal> has
|
||||||
|
been added to allow changing the location of duplicati’s
|
||||||
|
files.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -6,11 +6,17 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||||
|
|
||||||
## Highlights {#sec-release-22.05-highlights}
|
## Highlights {#sec-release-22.05-highlights}
|
||||||
|
|
||||||
|
- `security.acme.defaults` has been added to simplify configuring
|
||||||
|
settings for many certificates at once. This also opens up the
|
||||||
|
the option to use DNS-01 validation when using `enableACME` on
|
||||||
|
web server virtual hosts (e.g. `services.nginx.virtualHosts.*.enableACME`).
|
||||||
|
|
||||||
- PHP 8.1 is now available
|
- PHP 8.1 is now available
|
||||||
|
|
||||||
## New Services {#sec-release-22.05-new-services}
|
## New Services {#sec-release-22.05-new-services}
|
||||||
|
|
||||||
- [aesmd](https://github.com/intel/linux-sgx#install-the-intelr-sgx-psw), the Intel SGX Architectural Enclave Service Manager. Available as [services.aesmd](#opt-services.aesmd.enable).
|
- [aesmd](https://github.com/intel/linux-sgx#install-the-intelr-sgx-psw), the Intel SGX Architectural Enclave Service Manager. Available as [services.aesmd](#opt-services.aesmd.enable).
|
||||||
|
- [rootless Docker](https://docs.docker.com/engine/security/rootless/), a `systemd --user` Docker service which runs without root permissions. Available as [virtualisation.docker.rootless.enable](options.html#opt-virtualisation.docker.rootless.enable).
|
||||||
|
|
||||||
- [filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html), a lightweight shipper for forwarding and centralizing log data. Available as [services.filebeat](#opt-services.filebeat.enable).
|
- [filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html), a lightweight shipper for forwarding and centralizing log data. Available as [services.filebeat](#opt-services.filebeat.enable).
|
||||||
|
|
||||||
|
@ -35,6 +41,8 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||||
org-contrib, refer to the ones in `pkgs.emacsPackages.elpaPackages` and
|
org-contrib, refer to the ones in `pkgs.emacsPackages.elpaPackages` and
|
||||||
`pkgs.emacsPackages.nongnuPackages` where the new versions will release.
|
`pkgs.emacsPackages.nongnuPackages` where the new versions will release.
|
||||||
|
|
||||||
|
- `services.kubernetes.addons.dashboard` was removed due to it being an outdated version.
|
||||||
|
|
||||||
- The `wafHook` hook now honors `NIX_BUILD_CORES` when `enableParallelBuilding` is not set explicitly. Packages can restore the old behaviour by setting `enableParallelBuilding=false`.
|
- The `wafHook` hook now honors `NIX_BUILD_CORES` when `enableParallelBuilding` is not set explicitly. Packages can restore the old behaviour by setting `enableParallelBuilding=false`.
|
||||||
|
|
||||||
- `pkgs.claws-mail-gtk2`, representing Claws Mail's older release version three, was removed in order to get rid of Python 2.
|
- `pkgs.claws-mail-gtk2`, representing Claws Mail's older release version three, was removed in order to get rid of Python 2.
|
||||||
|
@ -45,6 +53,15 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||||
|
|
||||||
- If you previously used `/etc/docker/daemon.json`, you need to incorporate the changes into the new option `virtualisation.docker.daemon.settings`.
|
- If you previously used `/etc/docker/daemon.json`, you need to incorporate the changes into the new option `virtualisation.docker.daemon.settings`.
|
||||||
|
|
||||||
|
- The `autorestic` package has been upgraded from 1.3.0 to 1.5.0 which introduces breaking changes in config file, check [their migration guide](https://autorestic.vercel.app/migration/1.4_1.5) for more details.
|
||||||
|
|
||||||
|
- For `pkgs.python3.pkgs.ipython`, its direct dependency `pkgs.python3.pkgs.matplotlib-inline`
|
||||||
|
(which is really an adapter to integrate matplotlib in ipython if it is installed) does
|
||||||
|
not depend on `pkgs.python3.pkgs.matplotlib` anymore.
|
||||||
|
This is closer to a non-Nix install of ipython.
|
||||||
|
This has the added benefit to reduce the closure size of `ipython` from ~400MB to ~160MB
|
||||||
|
(including ~100MB for python itself).
|
||||||
|
|
||||||
## Other Notable Changes {#sec-release-22.05-notable-changes}
|
## Other Notable Changes {#sec-release-22.05-notable-changes}
|
||||||
|
|
||||||
- The option [services.redis.servers](#opt-services.redis.servers) was added
|
- The option [services.redis.servers](#opt-services.redis.servers) was added
|
||||||
|
@ -73,6 +90,12 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||||
- The `services.unifi.openPorts` option default value of `true` is now deprecated and will be changed to `false` in 22.11.
|
- The `services.unifi.openPorts` option default value of `true` is now deprecated and will be changed to `false` in 22.11.
|
||||||
Configurations using this default will print a warning when rebuilt.
|
Configurations using this default will print a warning when rebuilt.
|
||||||
|
|
||||||
|
- `security.acme` certificates will now correctly check for CA
|
||||||
|
revokation before reaching their minimum age.
|
||||||
|
|
||||||
|
- Removing domains from `security.acme.certs._name_.extraDomainNames`
|
||||||
|
will now correctly remove those domains during rebuild/renew.
|
||||||
|
|
||||||
- The option
|
- The option
|
||||||
[services.ssh.enableAskPassword](#opt-services.ssh.enableAskPassword) was
|
[services.ssh.enableAskPassword](#opt-services.ssh.enableAskPassword) was
|
||||||
added, decoupling the setting of `SSH_ASKPASS` from
|
added, decoupling the setting of `SSH_ASKPASS` from
|
||||||
|
@ -80,3 +103,5 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||||
e.g. Wayland.
|
e.g. Wayland.
|
||||||
|
|
||||||
- The `services.stubby` module was converted to a [settings-style](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) configuration.
|
- The `services.stubby` module was converted to a [settings-style](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) configuration.
|
||||||
|
|
||||||
|
- The option `services.duplicati.dataDir` has been added to allow changing the location of duplicati's files.
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<title>Configuration Options</title>
|
<title>Configuration Options</title>
|
||||||
<variablelist xml:id="configuration-variable-list">
|
<variablelist xml:id="configuration-variable-list">
|
||||||
<xsl:for-each select="attrs">
|
<xsl:for-each select="attrs">
|
||||||
<xsl:variable name="id" select="concat('opt-', str:replace(str:replace(str:replace(attr[@name = 'name']/string/@value, '*', '_'), '<', '_'), '>', '_'))" />
|
<xsl:variable name="id" select="concat('opt-', str:replace(str:replace(str:replace(str:replace(attr[@name = 'name']/string/@value, '*', '_'), '<', '_'), '>', '_'), ':', '_'))" />
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term xlink:href="#{$id}">
|
<term xlink:href="#{$id}">
|
||||||
<xsl:attribute name="xml:id"><xsl:value-of select="$id"/></xsl:attribute>
|
<xsl:attribute name="xml:id"><xsl:value-of select="$id"/></xsl:attribute>
|
||||||
|
|
|
@ -296,7 +296,6 @@
|
||||||
./services/cluster/hadoop/default.nix
|
./services/cluster/hadoop/default.nix
|
||||||
./services/cluster/k3s/default.nix
|
./services/cluster/k3s/default.nix
|
||||||
./services/cluster/kubernetes/addons/dns.nix
|
./services/cluster/kubernetes/addons/dns.nix
|
||||||
./services/cluster/kubernetes/addons/dashboard.nix
|
|
||||||
./services/cluster/kubernetes/addon-manager.nix
|
./services/cluster/kubernetes/addon-manager.nix
|
||||||
./services/cluster/kubernetes/apiserver.nix
|
./services/cluster/kubernetes/apiserver.nix
|
||||||
./services/cluster/kubernetes/controller-manager.nix
|
./services/cluster/kubernetes/controller-manager.nix
|
||||||
|
@ -1187,6 +1186,7 @@
|
||||||
./virtualisation/oci-containers.nix
|
./virtualisation/oci-containers.nix
|
||||||
./virtualisation/cri-o.nix
|
./virtualisation/cri-o.nix
|
||||||
./virtualisation/docker.nix
|
./virtualisation/docker.nix
|
||||||
|
./virtualisation/docker-rootless.nix
|
||||||
./virtualisation/ecs-agent.nix
|
./virtualisation/ecs-agent.nix
|
||||||
./virtualisation/libvirtd.nix
|
./virtualisation/libvirtd.nix
|
||||||
./virtualisation/lxc.nix
|
./virtualisation/lxc.nix
|
||||||
|
|
|
@ -26,6 +26,6 @@ with lib;
|
||||||
###### implementation
|
###### implementation
|
||||||
config = mkIf config.programs.qt5ct.enable {
|
config = mkIf config.programs.qt5ct.enable {
|
||||||
environment.variables.QT_QPA_PLATFORMTHEME = "qt5ct";
|
environment.variables.QT_QPA_PLATFORMTHEME = "qt5ct";
|
||||||
environment.systemPackages = with pkgs; [ qt5ct ];
|
environment.systemPackages = with pkgs; [ libsForQt5.qt5ct ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
488
third_party/nixpkgs/nixos/modules/security/acme.nix
vendored
488
third_party/nixpkgs/nixos/modules/security/acme.nix
vendored
|
@ -3,6 +3,7 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.security.acme;
|
cfg = config.security.acme;
|
||||||
opt = options.security.acme;
|
opt = options.security.acme;
|
||||||
|
user = if cfg.useRoot then "root" else "acme";
|
||||||
|
|
||||||
# Used to calculate timer accuracy for coalescing
|
# Used to calculate timer accuracy for coalescing
|
||||||
numCerts = length (builtins.attrNames cfg.certs);
|
numCerts = length (builtins.attrNames cfg.certs);
|
||||||
|
@ -23,7 +24,7 @@ let
|
||||||
# security.acme.certs.<cert>.group on some of the services.
|
# security.acme.certs.<cert>.group on some of the services.
|
||||||
commonServiceConfig = {
|
commonServiceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
User = "acme";
|
User = user;
|
||||||
Group = mkDefault "acme";
|
Group = mkDefault "acme";
|
||||||
UMask = 0022;
|
UMask = 0022;
|
||||||
StateDirectoryMode = 750;
|
StateDirectoryMode = 750;
|
||||||
|
@ -101,12 +102,12 @@ let
|
||||||
# is configurable on a per-cert basis.
|
# is configurable on a per-cert basis.
|
||||||
userMigrationService = let
|
userMigrationService = let
|
||||||
script = with builtins; ''
|
script = with builtins; ''
|
||||||
chown -R acme .lego/accounts
|
chown -R ${user} .lego/accounts
|
||||||
'' + (concatStringsSep "\n" (mapAttrsToList (cert: data: ''
|
'' + (concatStringsSep "\n" (mapAttrsToList (cert: data: ''
|
||||||
for fixpath in ${escapeShellArg cert} .lego/${escapeShellArg cert}; do
|
for fixpath in ${escapeShellArg cert} .lego/${escapeShellArg cert}; do
|
||||||
if [ -d "$fixpath" ]; then
|
if [ -d "$fixpath" ]; then
|
||||||
chmod -R u=rwX,g=rX,o= "$fixpath"
|
chmod -R u=rwX,g=rX,o= "$fixpath"
|
||||||
chown -R acme:${data.group} "$fixpath"
|
chown -R ${user}:${data.group} "$fixpath"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
'') certConfigs));
|
'') certConfigs));
|
||||||
|
@ -128,7 +129,7 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
certToConfig = cert: data: let
|
certToConfig = cert: data: let
|
||||||
acmeServer = if data.server != null then data.server else cfg.server;
|
acmeServer = data.server;
|
||||||
useDns = data.dnsProvider != null;
|
useDns = data.dnsProvider != null;
|
||||||
destPath = "/var/lib/acme/${cert}";
|
destPath = "/var/lib/acme/${cert}";
|
||||||
selfsignedDeps = optionals (cfg.preliminarySelfsigned) [ "acme-selfsigned-${cert}.service" ];
|
selfsignedDeps = optionals (cfg.preliminarySelfsigned) [ "acme-selfsigned-${cert}.service" ];
|
||||||
|
@ -156,6 +157,7 @@ let
|
||||||
${toString data.ocspMustStaple} ${data.keyType}
|
${toString data.ocspMustStaple} ${data.keyType}
|
||||||
'';
|
'';
|
||||||
certDir = mkHash hashData;
|
certDir = mkHash hashData;
|
||||||
|
# TODO remove domainHash usage entirely. Waiting on go-acme/lego#1532
|
||||||
domainHash = mkHash "${concatStringsSep " " extraDomains} ${data.domain}";
|
domainHash = mkHash "${concatStringsSep " " extraDomains} ${data.domain}";
|
||||||
accountHash = (mkAccountHash acmeServer data);
|
accountHash = (mkAccountHash acmeServer data);
|
||||||
accountDir = accountDirRoot + accountHash;
|
accountDir = accountDirRoot + accountHash;
|
||||||
|
@ -210,7 +212,7 @@ let
|
||||||
description = "Renew ACME Certificate for ${cert}";
|
description = "Renew ACME Certificate for ${cert}";
|
||||||
wantedBy = [ "timers.target" ];
|
wantedBy = [ "timers.target" ];
|
||||||
timerConfig = {
|
timerConfig = {
|
||||||
OnCalendar = cfg.renewInterval;
|
OnCalendar = data.renewInterval;
|
||||||
Unit = "acme-${cert}.service";
|
Unit = "acme-${cert}.service";
|
||||||
Persistent = "yes";
|
Persistent = "yes";
|
||||||
|
|
||||||
|
@ -267,7 +269,7 @@ let
|
||||||
cat key.pem fullchain.pem > full.pem
|
cat key.pem fullchain.pem > full.pem
|
||||||
|
|
||||||
# Group might change between runs, re-apply it
|
# Group might change between runs, re-apply it
|
||||||
chown 'acme:${data.group}' *
|
chown '${user}:${data.group}' *
|
||||||
|
|
||||||
# Default permissions make the files unreadable by group + anon
|
# Default permissions make the files unreadable by group + anon
|
||||||
# Need to be readable by group
|
# Need to be readable by group
|
||||||
|
@ -322,7 +324,7 @@ let
|
||||||
fi
|
fi
|
||||||
'');
|
'');
|
||||||
} // optionalAttrs (data.listenHTTP != null && toInt (elemAt (splitString ":" data.listenHTTP) 1) < 1024) {
|
} // optionalAttrs (data.listenHTTP != null && toInt (elemAt (splitString ":" data.listenHTTP) 1) < 1024) {
|
||||||
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
|
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Working directory will be /tmp
|
# Working directory will be /tmp
|
||||||
|
@ -355,7 +357,7 @@ let
|
||||||
expiration_s=$[expiration_date - now]
|
expiration_s=$[expiration_date - now]
|
||||||
expiration_days=$[expiration_s / (3600 * 24)] # rounds down
|
expiration_days=$[expiration_s / (3600 * 24)] # rounds down
|
||||||
|
|
||||||
[[ $expiration_days -gt ${toString cfg.validMinDays} ]]
|
[[ $expiration_days -gt ${toString data.validMinDays} ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
${optionalString (data.webroot != null) ''
|
${optionalString (data.webroot != null) ''
|
||||||
|
@ -372,37 +374,40 @@ let
|
||||||
|
|
||||||
echo '${domainHash}' > domainhash.txt
|
echo '${domainHash}' > domainhash.txt
|
||||||
|
|
||||||
# Check if we can renew
|
# Check if we can renew.
|
||||||
if [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a -n "$(ls -1 accounts)" ]; then
|
# We can only renew if the list of domains has not changed.
|
||||||
|
if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a -n "$(ls -1 accounts)" ]; then
|
||||||
|
|
||||||
# When domains are updated, there's no need to do a full
|
# Even if a cert is not expired, it may be revoked by the CA.
|
||||||
# Lego run, but it's likely renew won't work if days is too low.
|
# Try to renew, and silently fail if the cert is not expired.
|
||||||
if [ -e certificates/domainhash.txt ] && cmp -s domainhash.txt certificates/domainhash.txt; then
|
# Avoids #85794 and resolves #129838
|
||||||
|
if ! lego ${renewOpts} --days ${toString data.validMinDays}; then
|
||||||
if is_expiration_skippable out/full.pem; then
|
if is_expiration_skippable out/full.pem; then
|
||||||
echo 1>&2 "nixos-acme: skipping renewal because expiration isn't within the coming ${toString cfg.validMinDays} days"
|
echo 1>&2 "nixos-acme: Ignoring failed renewal because expiration isn't within the coming ${toString data.validMinDays} days"
|
||||||
else
|
else
|
||||||
echo 1>&2 "nixos-acme: renewing now, because certificate expires within the configured ${toString cfg.validMinDays} days"
|
# High number to avoid Systemd reserved codes.
|
||||||
lego ${renewOpts} --days ${toString cfg.validMinDays}
|
exit 11
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
echo 1>&2 "certificate domain(s) have changed; will renew now"
|
|
||||||
# Any number > 90 works, but this one is over 9000 ;-)
|
|
||||||
lego ${renewOpts} --days 9001
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Otherwise do a full run
|
# Otherwise do a full run
|
||||||
else
|
elif ! lego ${runOpts}; then
|
||||||
lego ${runOpts}
|
# Produce a nice error for those doing their first nixos-rebuild with these certs
|
||||||
|
echo Failed to fetch certificates. \
|
||||||
|
This may mean your DNS records are set up incorrectly. \
|
||||||
|
${optionalString (cfg.preliminarySelfsigned) "Selfsigned certs are in place and dependant services will still start."}
|
||||||
|
# Exit 10 so that users can potentially amend SuccessExitStatus to ignore this error.
|
||||||
|
# High number to avoid Systemd reserved codes.
|
||||||
|
exit 10
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mv domainhash.txt certificates/
|
mv domainhash.txt certificates/
|
||||||
|
|
||||||
# Group might change between runs, re-apply it
|
# Group might change between runs, re-apply it
|
||||||
chown 'acme:${data.group}' certificates/*
|
chown '${user}:${data.group}' certificates/*
|
||||||
|
|
||||||
# Copy all certs to the "real" certs directory
|
# Copy all certs to the "real" certs directory
|
||||||
CERT='certificates/${keyName}.crt'
|
if ! cmp -s 'certificates/${keyName}.crt' out/fullchain.pem; then
|
||||||
if [ -e "$CERT" ] && ! cmp -s "$CERT" out/fullchain.pem; then
|
|
||||||
touch out/renewed
|
touch out/renewed
|
||||||
echo Installing new certificate
|
echo Installing new certificate
|
||||||
cp -vp 'certificates/${keyName}.crt' out/fullchain.pem
|
cp -vp 'certificates/${keyName}.crt' out/fullchain.pem
|
||||||
|
@ -421,7 +426,194 @@ let
|
||||||
|
|
||||||
certConfigs = mapAttrs certToConfig cfg.certs;
|
certConfigs = mapAttrs certToConfig cfg.certs;
|
||||||
|
|
||||||
certOpts = { name, ... }: {
|
# These options can be specified within
|
||||||
|
# security.acme.defaults or security.acme.certs.<name>
|
||||||
|
inheritableModule = isDefaults: { config, ... }: let
|
||||||
|
defaultAndText = name: default: {
|
||||||
|
# When ! isDefaults then this is the option declaration for the
|
||||||
|
# security.acme.certs.<name> path, which has the extra inheritDefaults
|
||||||
|
# option, which if disabled means that we can't inherit it
|
||||||
|
default = if isDefaults || ! config.inheritDefaults then default else cfg.defaults.${name};
|
||||||
|
# The docs however don't need to depend on inheritDefaults, they should
|
||||||
|
# stay constant. Though notably it wouldn't matter much, because to get
|
||||||
|
# the option information, a submodule with name `<name>` is evaluated
|
||||||
|
# without any definitions.
|
||||||
|
defaultText = if isDefaults then default else literalExpression "config.security.acme.defaults.${name}";
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
validMinDays = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
inherit (defaultAndText "validMinDays" 30) default defaultText;
|
||||||
|
description = "Minimum remaining validity before renewal in days.";
|
||||||
|
};
|
||||||
|
|
||||||
|
renewInterval = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
inherit (defaultAndText "renewInterval" "daily") default defaultText;
|
||||||
|
description = ''
|
||||||
|
Systemd calendar expression when to check for renewal. See
|
||||||
|
<citerefentry><refentrytitle>systemd.time</refentrytitle>
|
||||||
|
<manvolnum>7</manvolnum></citerefentry>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
enableDebugLogs = mkEnableOption "debug logging for this certificate" // {
|
||||||
|
inherit (defaultAndText "enableDebugLogs" true) default defaultText;
|
||||||
|
};
|
||||||
|
|
||||||
|
webroot = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
inherit (defaultAndText "webroot" null) default defaultText;
|
||||||
|
example = "/var/lib/acme/acme-challenge";
|
||||||
|
description = ''
|
||||||
|
Where the webroot of the HTTP vhost is located.
|
||||||
|
<filename>.well-known/acme-challenge/</filename> directory
|
||||||
|
will be created below the webroot if it doesn't exist.
|
||||||
|
<literal>http://example.org/.well-known/acme-challenge/</literal> must also
|
||||||
|
be available (notice unencrypted HTTP).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
server = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
inherit (defaultAndText "server" null) default defaultText;
|
||||||
|
description = ''
|
||||||
|
ACME Directory Resource URI. Defaults to Let's Encrypt's
|
||||||
|
production endpoint,
|
||||||
|
<link xlink:href="https://acme-v02.api.letsencrypt.org/directory"/>, if unset.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
email = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
inherit (defaultAndText "email" null) default defaultText;
|
||||||
|
description = ''
|
||||||
|
Email address for account creation and correspondence from the CA.
|
||||||
|
It is recommended to use the same email for all certs to avoid account
|
||||||
|
creation limits.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
inherit (defaultAndText "group" "acme") default defaultText;
|
||||||
|
description = "Group running the ACME client.";
|
||||||
|
};
|
||||||
|
|
||||||
|
reloadServices = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
inherit (defaultAndText "reloadServices" []) default defaultText;
|
||||||
|
description = ''
|
||||||
|
The list of systemd services to call <code>systemctl try-reload-or-restart</code>
|
||||||
|
on.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
postRun = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
inherit (defaultAndText "postRun" "") default defaultText;
|
||||||
|
example = "cp full.pem backup.pem";
|
||||||
|
description = ''
|
||||||
|
Commands to run after new certificates go live. Note that
|
||||||
|
these commands run as the root user.
|
||||||
|
|
||||||
|
Executed in the same directory with the new certificate.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
keyType = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
inherit (defaultAndText "keyType" "ec256") default defaultText;
|
||||||
|
description = ''
|
||||||
|
Key type to use for private keys.
|
||||||
|
For an up to date list of supported values check the --key-type option
|
||||||
|
at <link xlink:href="https://go-acme.github.io/lego/usage/cli/#usage"/>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
dnsProvider = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
inherit (defaultAndText "dnsProvider" null) default defaultText;
|
||||||
|
example = "route53";
|
||||||
|
description = ''
|
||||||
|
DNS Challenge provider. For a list of supported providers, see the "code"
|
||||||
|
field of the DNS providers listed at <link xlink:href="https://go-acme.github.io/lego/dns/"/>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
dnsResolver = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
inherit (defaultAndText "dnsResolver" null) default defaultText;
|
||||||
|
example = "1.1.1.1:53";
|
||||||
|
description = ''
|
||||||
|
Set the resolver to use for performing recursive DNS queries. Supported:
|
||||||
|
host:port. The default is to use the system resolvers, or Google's DNS
|
||||||
|
resolvers if the system's cannot be determined.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
credentialsFile = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
inherit (defaultAndText "credentialsFile" null) default defaultText;
|
||||||
|
description = ''
|
||||||
|
Path to an EnvironmentFile for the cert's service containing any required and
|
||||||
|
optional environment variables for your selected dnsProvider.
|
||||||
|
To find out what values you need to set, consult the documentation at
|
||||||
|
<link xlink:href="https://go-acme.github.io/lego/dns/"/> for the corresponding dnsProvider.
|
||||||
|
'';
|
||||||
|
example = "/var/src/secrets/example.org-route53-api-token";
|
||||||
|
};
|
||||||
|
|
||||||
|
dnsPropagationCheck = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
inherit (defaultAndText "dnsPropagationCheck" true) default defaultText;
|
||||||
|
description = ''
|
||||||
|
Toggles lego DNS propagation check, which is used alongside DNS-01
|
||||||
|
challenge to ensure the DNS entries required are available.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ocspMustStaple = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
inherit (defaultAndText "ocspMustStaple" false) default defaultText;
|
||||||
|
description = ''
|
||||||
|
Turns on the OCSP Must-Staple TLS extension.
|
||||||
|
Make sure you know what you're doing! See:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><link xlink:href="https://blog.apnic.net/2019/01/15/is-the-web-ready-for-ocsp-must-staple/" /></para></listitem>
|
||||||
|
<listitem><para><link xlink:href="https://blog.hboeck.de/archives/886-The-Problem-with-OCSP-Stapling-and-Must-Staple-and-why-Certificate-Revocation-is-still-broken.html" /></para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraLegoFlags = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
inherit (defaultAndText "extraLegoFlags" []) default defaultText;
|
||||||
|
description = ''
|
||||||
|
Additional global flags to pass to all lego commands.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraLegoRenewFlags = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
inherit (defaultAndText "extraLegoRenewFlags" []) default defaultText;
|
||||||
|
description = ''
|
||||||
|
Additional flags to pass to lego renew.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraLegoRunFlags = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
inherit (defaultAndText "extraLegoRunFlags" []) default defaultText;
|
||||||
|
description = ''
|
||||||
|
Additional flags to pass to lego run.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
certOpts = { name, config, ... }: {
|
||||||
options = {
|
options = {
|
||||||
# user option has been removed
|
# user option has been removed
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
|
@ -441,40 +633,11 @@ let
|
||||||
default = "_mkMergedOptionModule";
|
default = "_mkMergedOptionModule";
|
||||||
};
|
};
|
||||||
|
|
||||||
enableDebugLogs = mkEnableOption "debug logging for this certificate" // { default = cfg.enableDebugLogs; };
|
directory = mkOption {
|
||||||
|
type = types.str;
|
||||||
webroot = mkOption {
|
readOnly = true;
|
||||||
type = types.nullOr types.str;
|
default = "/var/lib/acme/${name}";
|
||||||
default = null;
|
description = "Directory where certificate and other state is stored.";
|
||||||
example = "/var/lib/acme/acme-challenge";
|
|
||||||
description = ''
|
|
||||||
Where the webroot of the HTTP vhost is located.
|
|
||||||
<filename>.well-known/acme-challenge/</filename> directory
|
|
||||||
will be created below the webroot if it doesn't exist.
|
|
||||||
<literal>http://example.org/.well-known/acme-challenge/</literal> must also
|
|
||||||
be available (notice unencrypted HTTP).
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
listenHTTP = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
example = ":1360";
|
|
||||||
description = ''
|
|
||||||
Interface and port to listen on to solve HTTP challenges
|
|
||||||
in the form [INTERFACE]:PORT.
|
|
||||||
If you use a port other than 80, you must proxy port 80 to this port.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
server = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
ACME Directory Resource URI. Defaults to Let's Encrypt's
|
|
||||||
production endpoint,
|
|
||||||
<link xlink:href="https://acme-v02.api.letsencrypt.org/directory"/>, if unset.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
domain = mkOption {
|
domain = mkOption {
|
||||||
|
@ -483,47 +646,6 @@ let
|
||||||
description = "Domain to fetch certificate for (defaults to the entry name).";
|
description = "Domain to fetch certificate for (defaults to the entry name).";
|
||||||
};
|
};
|
||||||
|
|
||||||
email = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = cfg.email;
|
|
||||||
defaultText = literalExpression "config.${opt.email}";
|
|
||||||
description = "Contact email address for the CA to be able to reach you.";
|
|
||||||
};
|
|
||||||
|
|
||||||
group = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "acme";
|
|
||||||
description = "Group running the ACME client.";
|
|
||||||
};
|
|
||||||
|
|
||||||
reloadServices = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = ''
|
|
||||||
The list of systemd services to call <code>systemctl try-reload-or-restart</code>
|
|
||||||
on.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
postRun = mkOption {
|
|
||||||
type = types.lines;
|
|
||||||
default = "";
|
|
||||||
example = "cp full.pem backup.pem";
|
|
||||||
description = ''
|
|
||||||
Commands to run after new certificates go live. Note that
|
|
||||||
these commands run as the root user.
|
|
||||||
|
|
||||||
Executed in the same directory with the new certificate.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
directory = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
readOnly = true;
|
|
||||||
default = "/var/lib/acme/${name}";
|
|
||||||
description = "Directory where certificate and other state is stored.";
|
|
||||||
};
|
|
||||||
|
|
||||||
extraDomainNames = mkOption {
|
extraDomainNames = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [];
|
default = [];
|
||||||
|
@ -538,92 +660,25 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
keyType = mkOption {
|
# This setting must be different for each configured certificate, otherwise
|
||||||
type = types.str;
|
# two or more renewals may fail to bind to the address. Hence, it is not in
|
||||||
default = "ec256";
|
# the inheritableOpts.
|
||||||
description = ''
|
listenHTTP = mkOption {
|
||||||
Key type to use for private keys.
|
|
||||||
For an up to date list of supported values check the --key-type option
|
|
||||||
at <link xlink:href="https://go-acme.github.io/lego/usage/cli/#usage"/>.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
dnsProvider = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
example = "route53";
|
example = ":1360";
|
||||||
description = ''
|
description = ''
|
||||||
DNS Challenge provider. For a list of supported providers, see the "code"
|
Interface and port to listen on to solve HTTP challenges
|
||||||
field of the DNS providers listed at <link xlink:href="https://go-acme.github.io/lego/dns/"/>.
|
in the form [INTERFACE]:PORT.
|
||||||
|
If you use a port other than 80, you must proxy port 80 to this port.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
dnsResolver = mkOption {
|
inheritDefaults = mkOption {
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
example = "1.1.1.1:53";
|
|
||||||
description = ''
|
|
||||||
Set the resolver to use for performing recursive DNS queries. Supported:
|
|
||||||
host:port. The default is to use the system resolvers, or Google's DNS
|
|
||||||
resolvers if the system's cannot be determined.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
credentialsFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
description = ''
|
|
||||||
Path to an EnvironmentFile for the cert's service containing any required and
|
|
||||||
optional environment variables for your selected dnsProvider.
|
|
||||||
To find out what values you need to set, consult the documentation at
|
|
||||||
<link xlink:href="https://go-acme.github.io/lego/dns/"/> for the corresponding dnsProvider.
|
|
||||||
'';
|
|
||||||
example = "/var/src/secrets/example.org-route53-api-token";
|
|
||||||
};
|
|
||||||
|
|
||||||
dnsPropagationCheck = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
default = true;
|
||||||
description = ''
|
example = true;
|
||||||
Toggles lego DNS propagation check, which is used alongside DNS-01
|
description = "Whether to inherit values set in `security.acme.defaults` or not.";
|
||||||
challenge to ensure the DNS entries required are available.
|
type = lib.types.bool;
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
ocspMustStaple = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Turns on the OCSP Must-Staple TLS extension.
|
|
||||||
Make sure you know what you're doing! See:
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem><para><link xlink:href="https://blog.apnic.net/2019/01/15/is-the-web-ready-for-ocsp-must-staple/" /></para></listitem>
|
|
||||||
<listitem><para><link xlink:href="https://blog.hboeck.de/archives/886-The-Problem-with-OCSP-Stapling-and-Must-Staple-and-why-Certificate-Revocation-is-still-broken.html" /></para></listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extraLegoFlags = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = ''
|
|
||||||
Additional global flags to pass to all lego commands.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extraLegoRenewFlags = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = ''
|
|
||||||
Additional flags to pass to lego renew.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extraLegoRunFlags = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = ''
|
|
||||||
Additional flags to pass to lego run.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -632,41 +687,6 @@ in {
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
security.acme = {
|
security.acme = {
|
||||||
|
|
||||||
enableDebugLogs = mkEnableOption "debug logging for all certificates by default" // { default = true; };
|
|
||||||
|
|
||||||
validMinDays = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 30;
|
|
||||||
description = "Minimum remaining validity before renewal in days.";
|
|
||||||
};
|
|
||||||
|
|
||||||
email = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Contact email address for the CA to be able to reach you.";
|
|
||||||
};
|
|
||||||
|
|
||||||
renewInterval = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "daily";
|
|
||||||
description = ''
|
|
||||||
Systemd calendar expression when to check for renewal. See
|
|
||||||
<citerefentry><refentrytitle>systemd.time</refentrytitle>
|
|
||||||
<manvolnum>7</manvolnum></citerefentry>.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
server = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
ACME Directory Resource URI. Defaults to Let's Encrypt's
|
|
||||||
production endpoint,
|
|
||||||
<link xlink:href="https://acme-v02.api.letsencrypt.org/directory"/>, if unset.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
preliminarySelfsigned = mkOption {
|
preliminarySelfsigned = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
|
@ -689,9 +709,31 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useRoot = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to use the root user when generating certs. This is not recommended
|
||||||
|
for security + compatiblity reasons. If a service requires root owned certificates
|
||||||
|
consider following the guide on "Using ACME with services demanding root
|
||||||
|
owned certificates" in the NixOS manual, and only using this as a fallback
|
||||||
|
or for testing.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
defaults = mkOption {
|
||||||
|
type = types.submodule (inheritableModule true);
|
||||||
|
description = ''
|
||||||
|
Default values inheritable by all configured certs. You can
|
||||||
|
use this to define options shared by all your certs. These defaults
|
||||||
|
can also be ignored on a per-cert basis using the
|
||||||
|
`security.acme.certs.''${cert}.inheritDefaults' option.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
certs = mkOption {
|
certs = mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = with types; attrsOf (submodule certOpts);
|
type = with types; attrsOf (submodule [ (inheritableModule false) certOpts ]);
|
||||||
description = ''
|
description = ''
|
||||||
Attribute set of certificates to get signed and renewed. Creates
|
Attribute set of certificates to get signed and renewed. Creates
|
||||||
<literal>acme-''${cert}.{service,timer}</literal> systemd units for
|
<literal>acme-''${cert}.{service,timer}</literal> systemd units for
|
||||||
|
@ -722,12 +764,16 @@ in {
|
||||||
|
|
||||||
To use the let's encrypt staging server, use security.acme.server =
|
To use the let's encrypt staging server, use security.acme.server =
|
||||||
"https://acme-staging-v02.api.letsencrypt.org/directory".
|
"https://acme-staging-v02.api.letsencrypt.org/directory".
|
||||||
''
|
'')
|
||||||
)
|
|
||||||
(mkRemovedOptionModule [ "security" "acme" "directory" ] "ACME Directory is now hardcoded to /var/lib/acme and its permisisons are managed by systemd. See https://github.com/NixOS/nixpkgs/issues/53852 for more info.")
|
(mkRemovedOptionModule [ "security" "acme" "directory" ] "ACME Directory is now hardcoded to /var/lib/acme and its permisisons are managed by systemd. See https://github.com/NixOS/nixpkgs/issues/53852 for more info.")
|
||||||
(mkRemovedOptionModule [ "security" "acme" "preDelay" ] "This option has been removed. If you want to make sure that something executes before certificates are provisioned, add a RequiredBy=acme-\${cert}.service to the service you want to execute before the cert renewal")
|
(mkRemovedOptionModule [ "security" "acme" "preDelay" ] "This option has been removed. If you want to make sure that something executes before certificates are provisioned, add a RequiredBy=acme-\${cert}.service to the service you want to execute before the cert renewal")
|
||||||
(mkRemovedOptionModule [ "security" "acme" "activationDelay" ] "This option has been removed. If you want to make sure that something executes before certificates are provisioned, add a RequiredBy=acme-\${cert}.service to the service you want to execute before the cert renewal")
|
(mkRemovedOptionModule [ "security" "acme" "activationDelay" ] "This option has been removed. If you want to make sure that something executes before certificates are provisioned, add a RequiredBy=acme-\${cert}.service to the service you want to execute before the cert renewal")
|
||||||
(mkChangedOptionModule [ "security" "acme" "validMin" ] [ "security" "acme" "validMinDays" ] (config: config.security.acme.validMin / (24 * 3600)))
|
(mkChangedOptionModule [ "security" "acme" "validMin" ] [ "security" "acme" "defaults" "validMinDays" ] (config: config.security.acme.validMin / (24 * 3600)))
|
||||||
|
(mkChangedOptionModule [ "security" "acme" "validMinDays" ] [ "security" "acme" "defaults" "validMinDays" ] (config: config.security.acme.validMinDays))
|
||||||
|
(mkChangedOptionModule [ "security" "acme" "renewInterval" ] [ "security" "acme" "defaults" "renewInterval" ] (config: config.security.acme.renewInterval))
|
||||||
|
(mkChangedOptionModule [ "security" "acme" "email" ] [ "security" "acme" "defaults" "email" ] (config: config.security.acme.email))
|
||||||
|
(mkChangedOptionModule [ "security" "acme" "server" ] [ "security" "acme" "defaults" "server" ] (config: config.security.acme.server))
|
||||||
|
(mkChangedOptionModule [ "security" "acme" "enableDebugLogs" ] [ "security" "acme" "defaults" "enableDebugLogs" ] (config: config.security.acme.enableDebugLogs))
|
||||||
];
|
];
|
||||||
|
|
||||||
config = mkMerge [
|
config = mkMerge [
|
||||||
|
@ -842,8 +888,8 @@ in {
|
||||||
# Create some targets which can be depended on to be "active" after cert renewals
|
# Create some targets which can be depended on to be "active" after cert renewals
|
||||||
finishedTargets = mapAttrs' (cert: conf: nameValuePair "acme-finished-${cert}" {
|
finishedTargets = mapAttrs' (cert: conf: nameValuePair "acme-finished-${cert}" {
|
||||||
wantedBy = [ "default.target" ];
|
wantedBy = [ "default.target" ];
|
||||||
requires = [ "acme-${cert}.service" ] ++ conf.selfsignedDeps;
|
requires = [ "acme-${cert}.service" ];
|
||||||
after = [ "acme-${cert}.service" ] ++ conf.selfsignedDeps;
|
after = [ "acme-${cert}.service" ];
|
||||||
}) certConfigs;
|
}) certConfigs;
|
||||||
|
|
||||||
# Create targets to limit the number of simultaneous account creations
|
# Create targets to limit the number of simultaneous account creations
|
||||||
|
|
133
third_party/nixpkgs/nixos/modules/security/acme.xml
vendored
133
third_party/nixpkgs/nixos/modules/security/acme.xml
vendored
|
@ -7,8 +7,9 @@
|
||||||
<para>
|
<para>
|
||||||
NixOS supports automatic domain validation & certificate retrieval and
|
NixOS supports automatic domain validation & certificate retrieval and
|
||||||
renewal using the ACME protocol. Any provider can be used, but by default
|
renewal using the ACME protocol. Any provider can be used, but by default
|
||||||
NixOS uses Let's Encrypt. The alternative ACME client <literal>lego</literal>
|
NixOS uses Let's Encrypt. The alternative ACME client
|
||||||
is used under the hood.
|
<link xlink:href="https://go-acme.github.io/lego/">lego</link> is used under
|
||||||
|
the hood.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Automatic cert validation and configuration for Apache and Nginx virtual
|
Automatic cert validation and configuration for Apache and Nginx virtual
|
||||||
|
@ -29,7 +30,7 @@
|
||||||
<para>
|
<para>
|
||||||
You must also set an email address to be used when creating accounts with
|
You must also set an email address to be used when creating accounts with
|
||||||
Let's Encrypt. You can set this for all certs with
|
Let's Encrypt. You can set this for all certs with
|
||||||
<literal><xref linkend="opt-security.acme.email" /></literal>
|
<literal><xref linkend="opt-security.acme.defaults.email" /></literal>
|
||||||
and/or on a per-cert basis with
|
and/or on a per-cert basis with
|
||||||
<literal><xref linkend="opt-security.acme.certs._name_.email" /></literal>.
|
<literal><xref linkend="opt-security.acme.certs._name_.email" /></literal>.
|
||||||
This address is only used for registration and renewal reminders,
|
This address is only used for registration and renewal reminders,
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Alternatively, you can use a different ACME server by changing the
|
Alternatively, you can use a different ACME server by changing the
|
||||||
<literal><xref linkend="opt-security.acme.server" /></literal> option
|
<literal><xref linkend="opt-security.acme.defaults.server" /></literal> option
|
||||||
to a provider of your choosing, or just change the server for one cert with
|
to a provider of your choosing, or just change the server for one cert with
|
||||||
<literal><xref linkend="opt-security.acme.certs._name_.server" /></literal>.
|
<literal><xref linkend="opt-security.acme.certs._name_.server" /></literal>.
|
||||||
</para>
|
</para>
|
||||||
|
@ -60,12 +61,12 @@
|
||||||
= true;</literal> in a virtualHost config. We first create self-signed
|
= true;</literal> in a virtualHost config. We first create self-signed
|
||||||
placeholder certificates in place of the real ACME certs. The placeholder
|
placeholder certificates in place of the real ACME certs. The placeholder
|
||||||
certs are overwritten when the ACME certs arrive. For
|
certs are overwritten when the ACME certs arrive. For
|
||||||
<literal>foo.example.com</literal> the config would look like.
|
<literal>foo.example.com</literal> the config would look like this:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
<xref linkend="opt-security.acme.acceptTerms" /> = true;
|
<xref linkend="opt-security.acme.acceptTerms" /> = true;
|
||||||
<xref linkend="opt-security.acme.email" /> = "admin+acme@example.com";
|
<xref linkend="opt-security.acme.defaults.email" /> = "admin+acme@example.com";
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
<link linkend="opt-services.nginx.enable">enable</link> = true;
|
<link linkend="opt-services.nginx.enable">enable</link> = true;
|
||||||
<link linkend="opt-services.nginx.virtualHosts">virtualHosts</link> = {
|
<link linkend="opt-services.nginx.virtualHosts">virtualHosts</link> = {
|
||||||
|
@ -114,7 +115,7 @@ services.nginx = {
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
<xref linkend="opt-security.acme.acceptTerms" /> = true;
|
<xref linkend="opt-security.acme.acceptTerms" /> = true;
|
||||||
<xref linkend="opt-security.acme.email" /> = "admin+acme@example.com";
|
<xref linkend="opt-security.acme.defaults.email" /> = "admin+acme@example.com";
|
||||||
|
|
||||||
# /var/lib/acme/.challenges must be writable by the ACME user
|
# /var/lib/acme/.challenges must be writable by the ACME user
|
||||||
# and readable by the Nginx user. The easiest way to achieve
|
# and readable by the Nginx user. The easiest way to achieve
|
||||||
|
@ -218,7 +219,7 @@ services.bind = {
|
||||||
|
|
||||||
# Now we can configure ACME
|
# Now we can configure ACME
|
||||||
<xref linkend="opt-security.acme.acceptTerms" /> = true;
|
<xref linkend="opt-security.acme.acceptTerms" /> = true;
|
||||||
<xref linkend="opt-security.acme.email" /> = "admin+acme@example.com";
|
<xref linkend="opt-security.acme.defaults.email" /> = "admin+acme@example.com";
|
||||||
<xref linkend="opt-security.acme.certs" />."example.com" = {
|
<xref linkend="opt-security.acme.certs" />."example.com" = {
|
||||||
<link linkend="opt-security.acme.certs._name_.domain">domain</link> = "*.example.com";
|
<link linkend="opt-security.acme.certs._name_.domain">domain</link> = "*.example.com";
|
||||||
<link linkend="opt-security.acme.certs._name_.dnsProvider">dnsProvider</link> = "rfc2136";
|
<link linkend="opt-security.acme.certs._name_.dnsProvider">dnsProvider</link> = "rfc2136";
|
||||||
|
@ -231,10 +232,22 @@ services.bind = {
|
||||||
<para>
|
<para>
|
||||||
The <filename>dnskeys.conf</filename> and <filename>certs.secret</filename>
|
The <filename>dnskeys.conf</filename> and <filename>certs.secret</filename>
|
||||||
must be kept secure and thus you should not keep their contents in your
|
must be kept secure and thus you should not keep their contents in your
|
||||||
Nix config. Instead, generate them one time with these commands:
|
Nix config. Instead, generate them one time with a systemd service:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
|
systemd.services.dns-rfc2136-conf = {
|
||||||
|
requiredBy = ["acme-example.com.service", "bind.service"];
|
||||||
|
before = ["acme-example.com.service", "bind.service"];
|
||||||
|
unitConfig = {
|
||||||
|
ConditionPathExists = "!/var/lib/secrets/dnskeys.conf";
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
UMask = 0077;
|
||||||
|
};
|
||||||
|
path = [ pkgs.bind ];
|
||||||
|
script = ''
|
||||||
mkdir -p /var/lib/secrets
|
mkdir -p /var/lib/secrets
|
||||||
tsig-keygen rfc2136key.example.com > /var/lib/secrets/dnskeys.conf
|
tsig-keygen rfc2136key.example.com > /var/lib/secrets/dnskeys.conf
|
||||||
chown named:root /var/lib/secrets/dnskeys.conf
|
chown named:root /var/lib/secrets/dnskeys.conf
|
||||||
|
@ -250,6 +263,8 @@ RFC2136_TSIG_KEY='rfc2136key.example.com'
|
||||||
RFC2136_TSIG_SECRET='your secret key'
|
RFC2136_TSIG_SECRET='your secret key'
|
||||||
EOF
|
EOF
|
||||||
chmod 400 /var/lib/secrets/certs.secret
|
chmod 400 /var/lib/secrets/certs.secret
|
||||||
|
'';
|
||||||
|
};
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -258,6 +273,106 @@ chmod 400 /var/lib/secrets/certs.secret
|
||||||
journalctl -fu acme-example.com.service</literal> and watching its log output.
|
journalctl -fu acme-example.com.service</literal> and watching its log output.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section xml:id="module-security-acme-config-dns-with-vhosts">
|
||||||
|
<title>Using DNS validation with web server virtual hosts</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
It is possible to use DNS-01 validation with all certificates,
|
||||||
|
including those automatically configured via the Nginx/Apache
|
||||||
|
<literal><link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link></literal>
|
||||||
|
option. This configuration pattern is fully
|
||||||
|
supported and part of the module's test suite for Nginx + Apache.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
You must follow the guide above on configuring DNS-01 validation
|
||||||
|
first, however instead of setting the options for one certificate
|
||||||
|
(e.g. <xref linkend="opt-security.acme.certs._name_.dnsProvider" />)
|
||||||
|
you will set them as defaults
|
||||||
|
(e.g. <xref linkend="opt-security.acme.defaults.dnsProvider" />).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
# Configure ACME appropriately
|
||||||
|
<xref linkend="opt-security.acme.acceptTerms" /> = true;
|
||||||
|
<xref linkend="opt-security.acme.defaults.email" /> = "admin+acme@example.com";
|
||||||
|
<xref linkend="opt-security.acme.defaults" /> = {
|
||||||
|
<link linkend="opt-security.acme.defaults.dnsProvider">dnsProvider</link> = "rfc2136";
|
||||||
|
<link linkend="opt-security.acme.defaults.credentialsFile">credentialsFile</link> = "/var/lib/secrets/certs.secret";
|
||||||
|
# We don't need to wait for propagation since this is a local DNS server
|
||||||
|
<link linkend="opt-security.acme.defaults.dnsPropagationCheck">dnsPropagationCheck</link> = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# For each virtual host you would like to use DNS-01 validation with,
|
||||||
|
# set acmeRoot = null
|
||||||
|
services.nginx = {
|
||||||
|
<link linkend="opt-services.nginx.enable">enable</link> = true;
|
||||||
|
<link linkend="opt-services.nginx.virtualHosts">virtualHosts</link> = {
|
||||||
|
"foo.example.com" = {
|
||||||
|
<link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> = true;
|
||||||
|
<link linkend="opt-services.nginx.virtualHosts._name_.acmeRoot">acmeRoot</link> = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
And that's it! Next time your configuration is rebuilt, or when
|
||||||
|
you add a new virtualHost, it will be DNS-01 validated.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section xml:id="module-security-acme-root-owned">
|
||||||
|
<title>Using ACME with services demanding root owned certificates</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Some services refuse to start if the configured certificate files
|
||||||
|
are not owned by root. PostgreSQL and OpenSMTPD are examples of these.
|
||||||
|
There is no way to change the user the ACME module uses (it will always be
|
||||||
|
<literal>acme</literal>), however you can use systemd's
|
||||||
|
<literal>LoadCredential</literal> feature to resolve this elegantly.
|
||||||
|
Below is an example configuration for OpenSMTPD, but this pattern
|
||||||
|
can be applied to any service.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
# Configure ACME however you like (DNS or HTTP validation), adding
|
||||||
|
# the following configuration for the relevant certificate.
|
||||||
|
# Note: You cannot use `systemctl reload` here as that would mean
|
||||||
|
# the LoadCredential configuration below would be skipped and
|
||||||
|
# the service would continue to use old certificates.
|
||||||
|
security.acme.certs."mail.example.com".postRun = ''
|
||||||
|
systemctl restart opensmtpd
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Now you must augment OpenSMTPD's systemd service to load
|
||||||
|
# the certificate files.
|
||||||
|
<link linkend="opt-systemd.services._name_.requires">systemd.services.opensmtpd.requires</link> = ["acme-finished-mail.example.com.target"];
|
||||||
|
<link linkend="opt-systemd.services._name_.serviceConfig">systemd.services.opensmtpd.serviceConfig.LoadCredential</link> = let
|
||||||
|
certDir = config.security.acme.certs."mail.example.com".directory;
|
||||||
|
in [
|
||||||
|
"cert.pem:${certDir}/cert.pem"
|
||||||
|
"key.pem:${certDir}/key.pem"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Finally, configure OpenSMTPD to use these certs.
|
||||||
|
services.opensmtpd = let
|
||||||
|
credsDir = "/run/credentials/opensmtpd.service";
|
||||||
|
in {
|
||||||
|
enable = true;
|
||||||
|
setSendmail = false;
|
||||||
|
serverConfiguration = ''
|
||||||
|
pki mail.example.com cert "${credsDir}/cert.pem"
|
||||||
|
pki mail.example.com key "${credsDir}/key.pem"
|
||||||
|
listen on localhost tls pki mail.example.com
|
||||||
|
action act1 relay host smtp://127.0.0.1:10027
|
||||||
|
match for local action act1
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section xml:id="module-security-acme-regenerate">
|
<section xml:id="module-security-acme-regenerate">
|
||||||
<title>Regenerating certificates</title>
|
<title>Regenerating certificates</title>
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,20 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dataDir = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/var/lib/duplicati";
|
||||||
|
description = ''
|
||||||
|
The directory where Duplicati stores its data files.
|
||||||
|
|
||||||
|
<note><para>
|
||||||
|
If left as the default value this directory will automatically be created
|
||||||
|
before the Duplicati server starts, otherwise you are responsible for ensuring
|
||||||
|
the directory exists with appropriate ownership and permissions.
|
||||||
|
</para></note>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
interface = mkOption {
|
interface = mkOption {
|
||||||
default = "127.0.0.1";
|
default = "127.0.0.1";
|
||||||
type = types.str;
|
type = types.str;
|
||||||
|
@ -45,20 +59,23 @@ in
|
||||||
description = "Duplicati backup";
|
description = "Duplicati backup";
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = mkMerge [
|
||||||
|
{
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
Group = "duplicati";
|
Group = "duplicati";
|
||||||
StateDirectory = "duplicati";
|
ExecStart = "${pkgs.duplicati}/bin/duplicati-server --webservice-interface=${cfg.interface} --webservice-port=${toString cfg.port} --server-datafolder=${cfg.dataDir}";
|
||||||
ExecStart = "${pkgs.duplicati}/bin/duplicati-server --webservice-interface=${cfg.interface} --webservice-port=${toString cfg.port} --server-datafolder=/var/lib/duplicati";
|
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
};
|
}
|
||||||
|
(mkIf (cfg.dataDir == "/var/lib/duplicati") {
|
||||||
|
StateDirectory = "duplicati";
|
||||||
|
})
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users = lib.optionalAttrs (cfg.user == "duplicati") {
|
users.users = lib.optionalAttrs (cfg.user == "duplicati") {
|
||||||
duplicati = {
|
duplicati = {
|
||||||
uid = config.ids.uids.duplicati;
|
uid = config.ids.uids.duplicati;
|
||||||
home = "/var/lib/duplicati";
|
home = cfg.dataDir;
|
||||||
createHome = true;
|
|
||||||
group = "duplicati";
|
group = "duplicati";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,7 +58,7 @@ in
|
||||||
"spec" = { ... };
|
"spec" = { ... };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// import <nixpkgs/nixos/modules/services/cluster/kubernetes/dashboard.nix> { cfg = config.services.kubernetes; };
|
// import <nixpkgs/nixos/modules/services/cluster/kubernetes/dns.nix> { cfg = config.services.kubernetes; };
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,344 +0,0 @@
|
||||||
{ config, options, pkgs, lib, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.services.kubernetes.addons.dashboard;
|
|
||||||
opt = options.services.kubernetes.addons.dashboard;
|
|
||||||
in {
|
|
||||||
imports = [
|
|
||||||
(mkRenamedOptionModule [ "services" "kubernetes" "addons" "dashboard" "enableRBAC" ] [ "services" "kubernetes" "addons" "dashboard" "rbac" "enable" ])
|
|
||||||
];
|
|
||||||
|
|
||||||
options.services.kubernetes.addons.dashboard = {
|
|
||||||
enable = mkEnableOption "kubernetes dashboard addon";
|
|
||||||
|
|
||||||
extraArgs = mkOption {
|
|
||||||
description = "Extra arguments to append to the dashboard cmdline";
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
example = ["--enable-skip-login"];
|
|
||||||
};
|
|
||||||
|
|
||||||
rbac = mkOption {
|
|
||||||
description = "Role-based access control (RBAC) options";
|
|
||||||
default = {};
|
|
||||||
type = types.submodule {
|
|
||||||
options = {
|
|
||||||
enable = mkOption {
|
|
||||||
description = "Whether to enable role based access control is enabled for kubernetes dashboard";
|
|
||||||
type = types.bool;
|
|
||||||
default = elem "RBAC" config.services.kubernetes.apiserver.authorizationMode;
|
|
||||||
defaultText = literalExpression ''
|
|
||||||
elem "RBAC" config.${options.services.kubernetes.apiserver.authorizationMode}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
clusterAdmin = mkOption {
|
|
||||||
description = "Whether to assign cluster admin rights to the kubernetes dashboard";
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
version = mkOption {
|
|
||||||
description = "Which version of the kubernetes dashboard to deploy";
|
|
||||||
type = types.str;
|
|
||||||
default = "v1.10.1";
|
|
||||||
};
|
|
||||||
|
|
||||||
image = mkOption {
|
|
||||||
description = "Docker image to seed for the kubernetes dashboard container.";
|
|
||||||
type = types.attrs;
|
|
||||||
default = {
|
|
||||||
imageName = "k8s.gcr.io/kubernetes-dashboard-amd64";
|
|
||||||
imageDigest = "sha256:0ae6b69432e78069c5ce2bcde0fe409c5c4d6f0f4d9cd50a17974fea38898747";
|
|
||||||
finalImageTag = cfg.version;
|
|
||||||
sha256 = "01xrr4pwgr2hcjrjsi3d14ifpzdfbxzqpzxbk2fkbjb9zkv38zxy";
|
|
||||||
};
|
|
||||||
defaultText = literalExpression ''
|
|
||||||
{
|
|
||||||
imageName = "k8s.gcr.io/kubernetes-dashboard-amd64";
|
|
||||||
imageDigest = "sha256:0ae6b69432e78069c5ce2bcde0fe409c5c4d6f0f4d9cd50a17974fea38898747";
|
|
||||||
finalImageTag = config.${opt.version};
|
|
||||||
sha256 = "01xrr4pwgr2hcjrjsi3d14ifpzdfbxzqpzxbk2fkbjb9zkv38zxy";
|
|
||||||
};
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
services.kubernetes.kubelet.seedDockerImages = [(pkgs.dockerTools.pullImage cfg.image)];
|
|
||||||
|
|
||||||
services.kubernetes.addonManager.addons = {
|
|
||||||
kubernetes-dashboard-deployment = {
|
|
||||||
kind = "Deployment";
|
|
||||||
apiVersion = "apps/v1";
|
|
||||||
metadata = {
|
|
||||||
labels = {
|
|
||||||
k8s-addon = "kubernetes-dashboard.addons.k8s.io";
|
|
||||||
k8s-app = "kubernetes-dashboard";
|
|
||||||
version = cfg.version;
|
|
||||||
"kubernetes.io/cluster-service" = "true";
|
|
||||||
"addonmanager.kubernetes.io/mode" = "Reconcile";
|
|
||||||
};
|
|
||||||
name = "kubernetes-dashboard";
|
|
||||||
namespace = "kube-system";
|
|
||||||
};
|
|
||||||
spec = {
|
|
||||||
replicas = 1;
|
|
||||||
revisionHistoryLimit = 10;
|
|
||||||
selector.matchLabels.k8s-app = "kubernetes-dashboard";
|
|
||||||
template = {
|
|
||||||
metadata = {
|
|
||||||
labels = {
|
|
||||||
k8s-addon = "kubernetes-dashboard.addons.k8s.io";
|
|
||||||
k8s-app = "kubernetes-dashboard";
|
|
||||||
version = cfg.version;
|
|
||||||
"kubernetes.io/cluster-service" = "true";
|
|
||||||
};
|
|
||||||
annotations = {
|
|
||||||
"scheduler.alpha.kubernetes.io/critical-pod" = "";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
spec = {
|
|
||||||
priorityClassName = "system-cluster-critical";
|
|
||||||
containers = [{
|
|
||||||
name = "kubernetes-dashboard";
|
|
||||||
image = with cfg.image; "${imageName}:${finalImageTag}";
|
|
||||||
ports = [{
|
|
||||||
containerPort = 8443;
|
|
||||||
protocol = "TCP";
|
|
||||||
}];
|
|
||||||
resources = {
|
|
||||||
limits = {
|
|
||||||
cpu = "100m";
|
|
||||||
memory = "300Mi";
|
|
||||||
};
|
|
||||||
requests = {
|
|
||||||
cpu = "100m";
|
|
||||||
memory = "100Mi";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
args = ["--auto-generate-certificates"] ++ cfg.extraArgs;
|
|
||||||
volumeMounts = [{
|
|
||||||
name = "tmp-volume";
|
|
||||||
mountPath = "/tmp";
|
|
||||||
} {
|
|
||||||
name = "kubernetes-dashboard-certs";
|
|
||||||
mountPath = "/certs";
|
|
||||||
}];
|
|
||||||
livenessProbe = {
|
|
||||||
httpGet = {
|
|
||||||
scheme = "HTTPS";
|
|
||||||
path = "/";
|
|
||||||
port = 8443;
|
|
||||||
};
|
|
||||||
initialDelaySeconds = 30;
|
|
||||||
timeoutSeconds = 30;
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
volumes = [{
|
|
||||||
name = "kubernetes-dashboard-certs";
|
|
||||||
secret = {
|
|
||||||
secretName = "kubernetes-dashboard-certs";
|
|
||||||
};
|
|
||||||
} {
|
|
||||||
name = "tmp-volume";
|
|
||||||
emptyDir = {};
|
|
||||||
}];
|
|
||||||
serviceAccountName = "kubernetes-dashboard";
|
|
||||||
tolerations = [{
|
|
||||||
key = "node-role.kubernetes.io/master";
|
|
||||||
effect = "NoSchedule";
|
|
||||||
} {
|
|
||||||
key = "CriticalAddonsOnly";
|
|
||||||
operator = "Exists";
|
|
||||||
}];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
kubernetes-dashboard-svc = {
|
|
||||||
apiVersion = "v1";
|
|
||||||
kind = "Service";
|
|
||||||
metadata = {
|
|
||||||
labels = {
|
|
||||||
k8s-addon = "kubernetes-dashboard.addons.k8s.io";
|
|
||||||
k8s-app = "kubernetes-dashboard";
|
|
||||||
"kubernetes.io/cluster-service" = "true";
|
|
||||||
"kubernetes.io/name" = "KubeDashboard";
|
|
||||||
"addonmanager.kubernetes.io/mode" = "Reconcile";
|
|
||||||
};
|
|
||||||
name = "kubernetes-dashboard";
|
|
||||||
namespace = "kube-system";
|
|
||||||
};
|
|
||||||
spec = {
|
|
||||||
ports = [{
|
|
||||||
port = 443;
|
|
||||||
targetPort = 8443;
|
|
||||||
}];
|
|
||||||
selector.k8s-app = "kubernetes-dashboard";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
kubernetes-dashboard-sa = {
|
|
||||||
apiVersion = "v1";
|
|
||||||
kind = "ServiceAccount";
|
|
||||||
metadata = {
|
|
||||||
labels = {
|
|
||||||
k8s-app = "kubernetes-dashboard";
|
|
||||||
k8s-addon = "kubernetes-dashboard.addons.k8s.io";
|
|
||||||
"addonmanager.kubernetes.io/mode" = "Reconcile";
|
|
||||||
};
|
|
||||||
name = "kubernetes-dashboard";
|
|
||||||
namespace = "kube-system";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
kubernetes-dashboard-sec-certs = {
|
|
||||||
apiVersion = "v1";
|
|
||||||
kind = "Secret";
|
|
||||||
metadata = {
|
|
||||||
labels = {
|
|
||||||
k8s-app = "kubernetes-dashboard";
|
|
||||||
# Allows editing resource and makes sure it is created first.
|
|
||||||
"addonmanager.kubernetes.io/mode" = "EnsureExists";
|
|
||||||
};
|
|
||||||
name = "kubernetes-dashboard-certs";
|
|
||||||
namespace = "kube-system";
|
|
||||||
};
|
|
||||||
type = "Opaque";
|
|
||||||
};
|
|
||||||
kubernetes-dashboard-sec-kholder = {
|
|
||||||
apiVersion = "v1";
|
|
||||||
kind = "Secret";
|
|
||||||
metadata = {
|
|
||||||
labels = {
|
|
||||||
k8s-app = "kubernetes-dashboard";
|
|
||||||
# Allows editing resource and makes sure it is created first.
|
|
||||||
"addonmanager.kubernetes.io/mode" = "EnsureExists";
|
|
||||||
};
|
|
||||||
name = "kubernetes-dashboard-key-holder";
|
|
||||||
namespace = "kube-system";
|
|
||||||
};
|
|
||||||
type = "Opaque";
|
|
||||||
};
|
|
||||||
kubernetes-dashboard-cm = {
|
|
||||||
apiVersion = "v1";
|
|
||||||
kind = "ConfigMap";
|
|
||||||
metadata = {
|
|
||||||
labels = {
|
|
||||||
k8s-app = "kubernetes-dashboard";
|
|
||||||
# Allows editing resource and makes sure it is created first.
|
|
||||||
"addonmanager.kubernetes.io/mode" = "EnsureExists";
|
|
||||||
};
|
|
||||||
name = "kubernetes-dashboard-settings";
|
|
||||||
namespace = "kube-system";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} // (optionalAttrs cfg.rbac.enable
|
|
||||||
(let
|
|
||||||
subjects = [{
|
|
||||||
kind = "ServiceAccount";
|
|
||||||
name = "kubernetes-dashboard";
|
|
||||||
namespace = "kube-system";
|
|
||||||
}];
|
|
||||||
labels = {
|
|
||||||
k8s-app = "kubernetes-dashboard";
|
|
||||||
k8s-addon = "kubernetes-dashboard.addons.k8s.io";
|
|
||||||
"addonmanager.kubernetes.io/mode" = "Reconcile";
|
|
||||||
};
|
|
||||||
in
|
|
||||||
(if cfg.rbac.clusterAdmin then {
|
|
||||||
kubernetes-dashboard-crb = {
|
|
||||||
apiVersion = "rbac.authorization.k8s.io/v1";
|
|
||||||
kind = "ClusterRoleBinding";
|
|
||||||
metadata = {
|
|
||||||
name = "kubernetes-dashboard";
|
|
||||||
inherit labels;
|
|
||||||
};
|
|
||||||
roleRef = {
|
|
||||||
apiGroup = "rbac.authorization.k8s.io";
|
|
||||||
kind = "ClusterRole";
|
|
||||||
name = "cluster-admin";
|
|
||||||
};
|
|
||||||
inherit subjects;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
# Upstream role- and rolebinding as per:
|
|
||||||
# https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard.yaml
|
|
||||||
kubernetes-dashboard-role = {
|
|
||||||
apiVersion = "rbac.authorization.k8s.io/v1";
|
|
||||||
kind = "Role";
|
|
||||||
metadata = {
|
|
||||||
name = "kubernetes-dashboard-minimal";
|
|
||||||
namespace = "kube-system";
|
|
||||||
inherit labels;
|
|
||||||
};
|
|
||||||
rules = [
|
|
||||||
# Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret.
|
|
||||||
{
|
|
||||||
apiGroups = [""];
|
|
||||||
resources = ["secrets"];
|
|
||||||
verbs = ["create"];
|
|
||||||
}
|
|
||||||
# Allow Dashboard to create 'kubernetes-dashboard-settings' config map.
|
|
||||||
{
|
|
||||||
apiGroups = [""];
|
|
||||||
resources = ["configmaps"];
|
|
||||||
verbs = ["create"];
|
|
||||||
}
|
|
||||||
# Allow Dashboard to get, update and delete Dashboard exclusive secrets.
|
|
||||||
{
|
|
||||||
apiGroups = [""];
|
|
||||||
resources = ["secrets"];
|
|
||||||
resourceNames = ["kubernetes-dashboard-key-holder"];
|
|
||||||
verbs = ["get" "update" "delete"];
|
|
||||||
}
|
|
||||||
# Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
|
|
||||||
{
|
|
||||||
apiGroups = [""];
|
|
||||||
resources = ["configmaps"];
|
|
||||||
resourceNames = ["kubernetes-dashboard-settings"];
|
|
||||||
verbs = ["get" "update"];
|
|
||||||
}
|
|
||||||
# Allow Dashboard to get metrics from heapster.
|
|
||||||
{
|
|
||||||
apiGroups = [""];
|
|
||||||
resources = ["services"];
|
|
||||||
resourceNames = ["heapster"];
|
|
||||||
verbs = ["proxy"];
|
|
||||||
}
|
|
||||||
{
|
|
||||||
apiGroups = [""];
|
|
||||||
resources = ["services/proxy"];
|
|
||||||
resourceNames = ["heapster" "http:heapster:" "https:heapster:"];
|
|
||||||
verbs = ["get"];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
kubernetes-dashboard-rb = {
|
|
||||||
apiVersion = "rbac.authorization.k8s.io/v1";
|
|
||||||
kind = "RoleBinding";
|
|
||||||
metadata = {
|
|
||||||
name = "kubernetes-dashboard-minimal";
|
|
||||||
namespace = "kube-system";
|
|
||||||
inherit labels;
|
|
||||||
};
|
|
||||||
roleRef = {
|
|
||||||
apiGroup = "rbac.authorization.k8s.io";
|
|
||||||
kind = "Role";
|
|
||||||
name = "kubernetes-dashboard-minimal";
|
|
||||||
};
|
|
||||||
inherit subjects;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
));
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -106,6 +106,7 @@ let
|
||||||
in {
|
in {
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
|
(mkRemovedOptionModule [ "services" "kubernetes" "addons" "dashboard" ] "Removed due to it being an outdated version")
|
||||||
(mkRemovedOptionModule [ "services" "kubernetes" "verbose" ] "")
|
(mkRemovedOptionModule [ "services" "kubernetes" "verbose" ] "")
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
format = pkgs.formats.json { };
|
format = pkgs.formats.json { };
|
||||||
cfg = config.services.influxdb2;
|
cfg = config.services.influxdb2;
|
||||||
|
@ -9,12 +11,14 @@ in
|
||||||
options = {
|
options = {
|
||||||
services.influxdb2 = {
|
services.influxdb2 = {
|
||||||
enable = mkEnableOption "the influxdb2 server";
|
enable = mkEnableOption "the influxdb2 server";
|
||||||
|
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
default = pkgs.influxdb2-server;
|
default = pkgs.influxdb2-server;
|
||||||
defaultText = literalExpression "pkgs.influxdb2";
|
defaultText = literalExpression "pkgs.influxdb2";
|
||||||
description = "influxdb2 derivation to use.";
|
description = "influxdb2 derivation to use.";
|
||||||
type = types.package;
|
type = types.package;
|
||||||
};
|
};
|
||||||
|
|
||||||
settings = mkOption {
|
settings = mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
description = ''configuration options for influxdb2, see <link xlink:href="https://docs.influxdata.com/influxdb/v2.0/reference/config-options"/> for details.'';
|
description = ''configuration options for influxdb2, see <link xlink:href="https://docs.influxdata.com/influxdb/v2.0/reference/config-options"/> for details.'';
|
||||||
|
@ -28,18 +32,20 @@ in
|
||||||
assertion = !(builtins.hasAttr "bolt-path" cfg.settings) && !(builtins.hasAttr "engine-path" cfg.settings);
|
assertion = !(builtins.hasAttr "bolt-path" cfg.settings) && !(builtins.hasAttr "engine-path" cfg.settings);
|
||||||
message = "services.influxdb2.config: bolt-path and engine-path should not be set as they are managed by systemd";
|
message = "services.influxdb2.config: bolt-path and engine-path should not be set as they are managed by systemd";
|
||||||
}];
|
}];
|
||||||
|
|
||||||
systemd.services.influxdb2 = {
|
systemd.services.influxdb2 = {
|
||||||
description = "InfluxDB is an open-source, distributed, time series database";
|
description = "InfluxDB is an open-source, distributed, time series database";
|
||||||
documentation = [ "https://docs.influxdata.com/influxdb/" ];
|
documentation = [ "https://docs.influxdata.com/influxdb/" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
environment = {
|
environment = {
|
||||||
INFLUXD_CONFIG_PATH = "${configFile}";
|
INFLUXD_CONFIG_PATH = configFile;
|
||||||
};
|
};
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${cfg.package}/bin/influxd --bolt-path \${STATE_DIRECTORY}/influxd.bolt --engine-path \${STATE_DIRECTORY}/engine";
|
ExecStart = "${cfg.package}/bin/influxd --bolt-path \${STATE_DIRECTORY}/influxd.bolt --engine-path \${STATE_DIRECTORY}/engine";
|
||||||
StateDirectory = "influxdb2";
|
StateDirectory = "influxdb2";
|
||||||
DynamicUser = true;
|
User = "influxdb2";
|
||||||
|
Group = "influxdb2";
|
||||||
CapabilityBoundingSet = "";
|
CapabilityBoundingSet = "";
|
||||||
SystemCallFilter = "@system-service";
|
SystemCallFilter = "@system-service";
|
||||||
LimitNOFILE = 65536;
|
LimitNOFILE = 65536;
|
||||||
|
@ -47,6 +53,13 @@ in
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
users.extraUsers.influxdb2 = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "influxdb2";
|
||||||
|
};
|
||||||
|
|
||||||
|
users.extraGroups.influxdb2 = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
meta.maintainers = with lib.maintainers; [ nickcao ];
|
meta.maintainers = with lib.maintainers; [ nickcao ];
|
||||||
|
|
|
@ -54,7 +54,7 @@ in
|
||||||
|
|
||||||
systemd.packages = [ cfg.package ];
|
systemd.packages = [ cfg.package ];
|
||||||
|
|
||||||
services.udev.packages = [ pkgs.libmtp.bin ];
|
services.udev.packages = [ pkgs.libmtp ];
|
||||||
|
|
||||||
# Needed for unwrapped applications
|
# Needed for unwrapped applications
|
||||||
environment.variables.GIO_EXTRA_MODULES = [ "${cfg.package}/lib/gio/modules" ];
|
environment.variables.GIO_EXTRA_MODULES = [ "${cfg.package}/lib/gio/modules" ];
|
||||||
|
|
|
@ -19,7 +19,7 @@ let
|
||||||
description = "tuple of" + concatMapStrings (t: " (${t.description})") ts;
|
description = "tuple of" + concatMapStrings (t: " (${t.description})") ts;
|
||||||
};
|
};
|
||||||
level = ints.unsigned;
|
level = ints.unsigned;
|
||||||
special = enum [ "level auto" "level full-speed" "level disengage" ];
|
special = enum [ "level auto" "level full-speed" "level disengaged" ];
|
||||||
in
|
in
|
||||||
tuple [ (either level special) level level ];
|
tuple [ (either level special) level level ];
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ in {
|
||||||
|
|
||||||
LEVEL is the fan level to use: it can be an integer (0-7 with thinkpad_acpi),
|
LEVEL is the fan level to use: it can be an integer (0-7 with thinkpad_acpi),
|
||||||
"level auto" (to keep the default firmware behavior), "level full-speed" or
|
"level auto" (to keep the default firmware behavior), "level full-speed" or
|
||||||
"level disengage" (to run the fan as fast as possible).
|
"level disengaged" (to run the fan as fast as possible).
|
||||||
LOW is the temperature at which to step down to the previous level.
|
LOW is the temperature at which to step down to the previous level.
|
||||||
HIGH is the temperature at which to step up to the next level.
|
HIGH is the temperature at which to step up to the next level.
|
||||||
All numbers are integers.
|
All numbers are integers.
|
||||||
|
|
|
@ -145,7 +145,7 @@ in {
|
||||||
--config='${settingsFile}' \
|
--config='${settingsFile}' \
|
||||||
--registration='${registrationFile}'
|
--registration='${registrationFile}'
|
||||||
fi
|
fi
|
||||||
|
'' + lib.optionalString (pkgs.mautrix-telegram ? alembic) ''
|
||||||
# run automatic database init and migration scripts
|
# run automatic database init and migration scripts
|
||||||
${pkgs.mautrix-telegram.alembic}/bin/alembic -x config='${settingsFile}' upgrade head
|
${pkgs.mautrix-telegram.alembic}/bin/alembic -x config='${settingsFile}' upgrade head
|
||||||
'';
|
'';
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,66 +1,375 @@
|
||||||
{ config, pkgs, lib }:
|
srv:
|
||||||
serviceCfg: serviceDrv: iniKey: attrs:
|
{ configIniOfService
|
||||||
let
|
, srvsrht ? "${srv}srht" # Because "buildsrht" does not follow that pattern (missing an "s").
|
||||||
cfg = config.services.sourcehut;
|
, iniKey ? "${srv}.sr.ht"
|
||||||
cfgIni = cfg.settings."${iniKey}";
|
, webhooks ? false
|
||||||
pgSuperUser = config.services.postgresql.superUser;
|
, extraTimers ? {}
|
||||||
|
, mainService ? {}
|
||||||
|
, extraServices ? {}
|
||||||
|
, extraConfig ? {}
|
||||||
|
, port
|
||||||
|
}:
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
setupDB = pkgs.writeScript "${serviceDrv.pname}-gen-db" ''
|
with lib;
|
||||||
#! ${cfg.python}/bin/python
|
let
|
||||||
from ${serviceDrv.pname}.app import db
|
inherit (config.services) postgresql;
|
||||||
db.create()
|
redis = config.services.redis.servers."sourcehut-${srvsrht}";
|
||||||
'';
|
inherit (config.users) users;
|
||||||
|
cfg = config.services.sourcehut;
|
||||||
|
configIni = configIniOfService srv;
|
||||||
|
srvCfg = cfg.${srv};
|
||||||
|
baseService = serviceName: { allowStripe ? false }: extraService: let
|
||||||
|
runDir = "/run/sourcehut/${serviceName}";
|
||||||
|
rootDir = "/run/sourcehut/chroots/${serviceName}";
|
||||||
|
in
|
||||||
|
mkMerge [ extraService {
|
||||||
|
after = [ "network.target" ] ++
|
||||||
|
optional cfg.postgresql.enable "postgresql.service" ++
|
||||||
|
optional cfg.redis.enable "redis-sourcehut-${srvsrht}.service";
|
||||||
|
requires =
|
||||||
|
optional cfg.postgresql.enable "postgresql.service" ++
|
||||||
|
optional cfg.redis.enable "redis-sourcehut-${srvsrht}.service";
|
||||||
|
path = [ pkgs.gawk ];
|
||||||
|
environment.HOME = runDir;
|
||||||
|
serviceConfig = {
|
||||||
|
User = mkDefault srvCfg.user;
|
||||||
|
Group = mkDefault srvCfg.group;
|
||||||
|
RuntimeDirectory = [
|
||||||
|
"sourcehut/${serviceName}"
|
||||||
|
# Used by *srht-keys which reads ../config.ini
|
||||||
|
"sourcehut/${serviceName}/subdir"
|
||||||
|
"sourcehut/chroots/${serviceName}"
|
||||||
|
];
|
||||||
|
RuntimeDirectoryMode = "2750";
|
||||||
|
# No need for the chroot path once inside the chroot
|
||||||
|
InaccessiblePaths = [ "-+${rootDir}" ];
|
||||||
|
# g+rx is for group members (eg. fcgiwrap or nginx)
|
||||||
|
# to read Git/Mercurial repositories, buildlogs, etc.
|
||||||
|
# o+x is for intermediate directories created by BindPaths= and like,
|
||||||
|
# as they're owned by root:root.
|
||||||
|
UMask = "0026";
|
||||||
|
RootDirectory = rootDir;
|
||||||
|
RootDirectoryStartOnly = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
MountAPIVFS = true;
|
||||||
|
# config.ini is looked up in there, before /etc/srht/config.ini
|
||||||
|
# Note that it fails to be set in ExecStartPre=
|
||||||
|
WorkingDirectory = mkDefault ("-"+runDir);
|
||||||
|
BindReadOnlyPaths = [
|
||||||
|
builtins.storeDir
|
||||||
|
"/etc"
|
||||||
|
"/run/booted-system"
|
||||||
|
"/run/current-system"
|
||||||
|
"/run/systemd"
|
||||||
|
] ++
|
||||||
|
optional cfg.postgresql.enable "/run/postgresql" ++
|
||||||
|
optional cfg.redis.enable "/run/redis-sourcehut-${srvsrht}";
|
||||||
|
# LoadCredential= are unfortunately not available in ExecStartPre=
|
||||||
|
# Hence this one is run as root (the +) with RootDirectoryStartOnly=
|
||||||
|
# to reach credentials wherever they are.
|
||||||
|
# Note that each systemd service gets its own ${runDir}/config.ini file.
|
||||||
|
ExecStartPre = mkBefore [("+"+pkgs.writeShellScript "${serviceName}-credentials" ''
|
||||||
|
set -x
|
||||||
|
# Replace values begining with a '<' by the content of the file whose name is after.
|
||||||
|
gawk '{ if (match($0,/^([^=]+=)<(.+)/,m)) { getline f < m[2]; print m[1] f } else print $0 }' ${configIni} |
|
||||||
|
${optionalString (!allowStripe) "gawk '!/^stripe-secret-key=/' |"}
|
||||||
|
install -o ${srvCfg.user} -g root -m 400 /dev/stdin ${runDir}/config.ini
|
||||||
|
'')];
|
||||||
|
# The following options are only for optimizing:
|
||||||
|
# systemd-analyze security
|
||||||
|
AmbientCapabilities = "";
|
||||||
|
CapabilityBoundingSet = "";
|
||||||
|
# ProtectClock= adds DeviceAllow=char-rtc r
|
||||||
|
DeviceAllow = "";
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
PrivateMounts = true;
|
||||||
|
PrivateNetwork = mkDefault false;
|
||||||
|
PrivateUsers = true;
|
||||||
|
ProcSubset = "pid";
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
RemoveIPC = true;
|
||||||
|
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
#SocketBindAllow = [ "tcp:${toString srvCfg.port}" "tcp:${toString srvCfg.prometheusPort}" ];
|
||||||
|
#SocketBindDeny = "any";
|
||||||
|
SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"~@aio" "~@keyring" "~@memlock" "~@privileged" "~@resources" "~@timer"
|
||||||
|
"@chown" "@setuid"
|
||||||
|
];
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
};
|
||||||
|
} ];
|
||||||
in
|
in
|
||||||
with serviceCfg; with lib; recursiveUpdate
|
|
||||||
{
|
{
|
||||||
environment.HOME = statePath;
|
options.services.sourcehut.${srv} = {
|
||||||
path = [ config.services.postgresql.package ] ++ (attrs.path or [ ]);
|
enable = mkEnableOption "${srv} service";
|
||||||
restartTriggers = [ config.environment.etc."sr.ht/config.ini".source ];
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = srvsrht;
|
||||||
|
description = ''
|
||||||
|
User for ${srv}.sr.ht.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = srvsrht;
|
||||||
|
description = ''
|
||||||
|
Group for ${srv}.sr.ht.
|
||||||
|
Membership grants access to the Git/Mercurial repositories by default,
|
||||||
|
but not to the config.ini file (where secrets are).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = port;
|
||||||
|
description = ''
|
||||||
|
Port on which the "${srv}" backend should listen.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
redis = {
|
||||||
|
host = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "unix:/run/redis-sourcehut-${srvsrht}/redis.sock?db=0";
|
||||||
|
example = "redis://shared.wireguard:6379/0";
|
||||||
|
description = ''
|
||||||
|
The redis host URL. This is used for caching and temporary storage, and must
|
||||||
|
be shared between nodes (e.g. git1.sr.ht and git2.sr.ht), but need not be
|
||||||
|
shared between services. It may be shared between services, however, with no
|
||||||
|
ill effect, if this better suits your infrastructure.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresql = {
|
||||||
|
database = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "${srv}.sr.ht";
|
||||||
|
description = ''
|
||||||
|
PostgreSQL database name for the ${srv}.sr.ht service,
|
||||||
|
used if <xref linkend="opt-services.sourcehut.postgresql.enable"/> is <literal>true</literal>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
gunicorn = {
|
||||||
|
extraArgs = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = ["--timeout 120" "--workers 1" "--log-level=info"];
|
||||||
|
description = "Extra arguments passed to Gunicorn.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // optionalAttrs webhooks {
|
||||||
|
webhooks = {
|
||||||
|
extraArgs = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = ["--loglevel DEBUG" "--pool eventlet" "--without-heartbeat"];
|
||||||
|
description = "Extra arguments passed to the Celery responsible for webhooks.";
|
||||||
|
};
|
||||||
|
celeryConfig = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
description = "Content of the <literal>celeryconfig.py</literal> used by the Celery responsible for webhooks.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf (cfg.enable && srvCfg.enable) (mkMerge [ extraConfig {
|
||||||
|
users = {
|
||||||
|
users = {
|
||||||
|
"${srvCfg.user}" = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = mkDefault srvCfg.group;
|
||||||
|
description = mkDefault "sourcehut user for ${srv}.sr.ht";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
groups = {
|
||||||
|
"${srvCfg.group}" = { };
|
||||||
|
} // optionalAttrs (cfg.postgresql.enable
|
||||||
|
&& hasSuffix "0" (postgresql.settings.unix_socket_permissions or "")) {
|
||||||
|
"postgres".members = [ srvCfg.user ];
|
||||||
|
} // optionalAttrs (cfg.redis.enable
|
||||||
|
&& hasSuffix "0" (redis.settings.unixsocketperm or "")) {
|
||||||
|
"redis-sourcehut-${srvsrht}".members = [ srvCfg.user ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx = mkIf cfg.nginx.enable {
|
||||||
|
virtualHosts."${srv}.${cfg.settings."sr.ht".global-domain}" = mkMerge [ {
|
||||||
|
forceSSL = mkDefault true;
|
||||||
|
locations."/".proxyPass = "http://${cfg.listenAddress}:${toString srvCfg.port}";
|
||||||
|
locations."/static" = {
|
||||||
|
root = "${pkgs.sourcehut.${srvsrht}}/${pkgs.sourcehut.python.sitePackages}/${srvsrht}";
|
||||||
|
extraConfig = mkDefault ''
|
||||||
|
expires 30d;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
} cfg.nginx.virtualHost ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = mkIf cfg.postgresql.enable {
|
||||||
|
authentication = ''
|
||||||
|
local ${srvCfg.postgresql.database} ${srvCfg.user} trust
|
||||||
|
'';
|
||||||
|
ensureDatabases = [ srvCfg.postgresql.database ];
|
||||||
|
ensureUsers = map (name: {
|
||||||
|
inherit name;
|
||||||
|
ensurePermissions = { "DATABASE \"${srvCfg.postgresql.database}\"" = "ALL PRIVILEGES"; };
|
||||||
|
}) [srvCfg.user];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.sourcehut.services = mkDefault (filter (s: cfg.${s}.enable)
|
||||||
|
[ "builds" "dispatch" "git" "hg" "hub" "lists" "man" "meta" "pages" "paste" "todo" ]);
|
||||||
|
|
||||||
|
services.sourcehut.settings = mkMerge [
|
||||||
|
{
|
||||||
|
"${srv}.sr.ht".origin = mkDefault "https://${srv}.${cfg.settings."sr.ht".global-domain}";
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf cfg.postgresql.enable {
|
||||||
|
"${srv}.sr.ht".connection-string = mkDefault "postgresql:///${srvCfg.postgresql.database}?user=${srvCfg.user}&host=/run/postgresql";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
services.redis.servers."sourcehut-${srvsrht}" = mkIf cfg.redis.enable {
|
||||||
|
enable = true;
|
||||||
|
databases = 3;
|
||||||
|
syslog = true;
|
||||||
|
# TODO: set a more informed value
|
||||||
|
save = mkDefault [ [1800 10] [300 100] ];
|
||||||
|
settings = {
|
||||||
|
# TODO: set a more informed value
|
||||||
|
maxmemory = "128MB";
|
||||||
|
maxmemory-policy = "volatile-ttl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services = mkMerge [
|
||||||
|
{
|
||||||
|
"${srvsrht}" = baseService srvsrht { allowStripe = srv == "meta"; } (mkMerge [
|
||||||
|
{
|
||||||
|
description = "sourcehut ${srv}.sr.ht website service";
|
||||||
|
before = optional cfg.nginx.enable "nginx.service";
|
||||||
|
wants = optional cfg.nginx.enable "nginx.service";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
path = optional cfg.postgresql.enable postgresql.package;
|
||||||
|
# Beware: change in credentials' content will not trigger restart.
|
||||||
|
restartTriggers = [ configIni ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
User = user;
|
Restart = mkDefault "always";
|
||||||
Group = user;
|
#RestartSec = mkDefault "2min";
|
||||||
Restart = "always";
|
StateDirectory = [ "sourcehut/${srvsrht}" ];
|
||||||
WorkingDirectory = statePath;
|
StateDirectoryMode = "2750";
|
||||||
} // (if (cfg.statePath == "/var/lib/sourcehut/${serviceDrv.pname}") then {
|
ExecStart = "${cfg.python}/bin/gunicorn ${srvsrht}.app:app --name ${srvsrht} --bind ${cfg.listenAddress}:${toString srvCfg.port} " + concatStringsSep " " srvCfg.gunicorn.extraArgs;
|
||||||
StateDirectory = [ "sourcehut/${serviceDrv.pname}" ];
|
};
|
||||||
} else {})
|
preStart = let
|
||||||
;
|
version = pkgs.sourcehut.${srvsrht}.version;
|
||||||
|
stateDir = "/var/lib/sourcehut/${srvsrht}";
|
||||||
|
in mkBefore ''
|
||||||
|
set -x
|
||||||
|
# Use the /run/sourcehut/${srvsrht}/config.ini
|
||||||
|
# installed by a previous ExecStartPre= in baseService
|
||||||
|
cd /run/sourcehut/${srvsrht}
|
||||||
|
|
||||||
preStart = ''
|
if test ! -e ${stateDir}/db; then
|
||||||
if ! test -e ${statePath}/db; then
|
# Setup the initial database.
|
||||||
# Setup the initial database
|
# Note that it stamps the alembic head afterward
|
||||||
${setupDB}
|
${cfg.python}/bin/${srvsrht}-initdb
|
||||||
|
echo ${version} >${stateDir}/db
|
||||||
# Set the initial state of the database for future database upgrades
|
|
||||||
if test -e ${cfg.python}/bin/${serviceDrv.pname}-migrate; then
|
|
||||||
# Run alembic stamp head once to tell alembic the schema is up-to-date
|
|
||||||
${cfg.python}/bin/${serviceDrv.pname}-migrate stamp head
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf "%s" "${serviceDrv.version}" > ${statePath}/db
|
${optionalString cfg.settings.${iniKey}.migrate-on-upgrade ''
|
||||||
fi
|
if [ "$(cat ${stateDir}/db)" != "${version}" ]; then
|
||||||
|
|
||||||
# Update copy of each users' profile to the latest
|
|
||||||
# See https://lists.sr.ht/~sircmpwn/sr.ht-admins/<20190302181207.GA13778%40cirno.my.domain>
|
|
||||||
if ! test -e ${statePath}/webhook; then
|
|
||||||
# Update ${iniKey}'s users' profile copy to the latest
|
|
||||||
${cfg.python}/bin/srht-update-profiles ${iniKey}
|
|
||||||
|
|
||||||
touch ${statePath}/webhook
|
|
||||||
fi
|
|
||||||
|
|
||||||
${optionalString (builtins.hasAttr "migrate-on-upgrade" cfgIni && cfgIni.migrate-on-upgrade == "yes") ''
|
|
||||||
if [ "$(cat ${statePath}/db)" != "${serviceDrv.version}" ]; then
|
|
||||||
# Manage schema migrations using alembic
|
# Manage schema migrations using alembic
|
||||||
${cfg.python}/bin/${serviceDrv.pname}-migrate -a upgrade head
|
${cfg.python}/bin/${srvsrht}-migrate -a upgrade head
|
||||||
|
echo ${version} >${stateDir}/db
|
||||||
# Mark down current package version
|
|
||||||
printf "%s" "${serviceDrv.version}" > ${statePath}/db
|
|
||||||
fi
|
fi
|
||||||
''}
|
''}
|
||||||
|
|
||||||
${attrs.preStart or ""}
|
# Update copy of each users' profile to the latest
|
||||||
|
# See https://lists.sr.ht/~sircmpwn/sr.ht-admins/<20190302181207.GA13778%40cirno.my.domain>
|
||||||
|
if test ! -e ${stateDir}/webhook; then
|
||||||
|
# Update ${iniKey}'s users' profile copy to the latest
|
||||||
|
${cfg.python}/bin/srht-update-profiles ${iniKey}
|
||||||
|
touch ${stateDir}/webhook
|
||||||
|
fi
|
||||||
'';
|
'';
|
||||||
|
} mainService ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf webhooks {
|
||||||
|
"${srvsrht}-webhooks" = baseService "${srvsrht}-webhooks" {}
|
||||||
|
{
|
||||||
|
description = "sourcehut ${srv}.sr.ht webhooks service";
|
||||||
|
after = [ "${srvsrht}.service" ];
|
||||||
|
wantedBy = [ "${srvsrht}.service" ];
|
||||||
|
partOf = [ "${srvsrht}.service" ];
|
||||||
|
preStart = ''
|
||||||
|
cp ${pkgs.writeText "${srvsrht}-webhooks-celeryconfig.py" srvCfg.webhooks.celeryConfig} \
|
||||||
|
/run/sourcehut/${srvsrht}-webhooks/celeryconfig.py
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
Restart = "always";
|
||||||
|
ExecStart = "${cfg.python}/bin/celery --app ${srvsrht}.webhooks worker --hostname ${srvsrht}-webhooks@%%h " + concatStringsSep " " srvCfg.webhooks.extraArgs;
|
||||||
|
# Avoid crashing: os.getloadavg()
|
||||||
|
ProcSubset = mkForce "all";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(mapAttrs (timerName: timer: (baseService timerName {} (mkMerge [
|
||||||
|
{
|
||||||
|
description = "sourcehut ${timerName} service";
|
||||||
|
after = [ "network.target" "${srvsrht}.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${cfg.python}/bin/${timerName}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(timer.service or {})
|
||||||
|
]))) extraTimers)
|
||||||
|
|
||||||
|
(mapAttrs (serviceName: extraService: baseService serviceName {} (mkMerge [
|
||||||
|
{
|
||||||
|
description = "sourcehut ${serviceName} service";
|
||||||
|
# So that extraServices have the PostgreSQL database initialized.
|
||||||
|
after = [ "${srvsrht}.service" ];
|
||||||
|
wantedBy = [ "${srvsrht}.service" ];
|
||||||
|
partOf = [ "${srvsrht}.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
Restart = mkDefault "always";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
extraService
|
||||||
|
])) extraServices)
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.timers = mapAttrs (timerName: timer:
|
||||||
|
{
|
||||||
|
description = "sourcehut timer for ${timerName}";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
inherit (timer) timerConfig;
|
||||||
|
}) extraTimers;
|
||||||
|
} ]);
|
||||||
}
|
}
|
||||||
(builtins.removeAttrs attrs [ "path" "preStart" ])
|
|
||||||
|
|
|
@ -14,13 +14,12 @@
|
||||||
<title>Basic usage</title>
|
<title>Basic usage</title>
|
||||||
<para>
|
<para>
|
||||||
Sourcehut is a Python and Go based set of applications.
|
Sourcehut is a Python and Go based set of applications.
|
||||||
<literal><link linkend="opt-services.sourcehut.enable">services.sourcehut</link></literal>
|
This NixOS module also provides basic configuration integrating Sourcehut into locally running
|
||||||
by default will use
|
|
||||||
<literal><link linkend="opt-services.nginx.enable">services.nginx</link></literal>,
|
<literal><link linkend="opt-services.nginx.enable">services.nginx</link></literal>,
|
||||||
<literal><link linkend="opt-services.nginx.enable">services.redis</link></literal>,
|
<literal><link linkend="opt-services.redis.servers">services.redis.servers.sourcehut</link></literal>,
|
||||||
<literal><link linkend="opt-services.nginx.enable">services.cron</link></literal>,
|
<literal><link linkend="opt-services.postfix.enable">services.postfix</link></literal>
|
||||||
and
|
and
|
||||||
<literal><link linkend="opt-services.postgresql.enable">services.postgresql</link></literal>.
|
<literal><link linkend="opt-services.postgresql.enable">services.postgresql</link></literal> services.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -42,18 +41,23 @@ in {
|
||||||
|
|
||||||
services.sourcehut = {
|
services.sourcehut = {
|
||||||
<link linkend="opt-services.sourcehut.enable">enable</link> = true;
|
<link linkend="opt-services.sourcehut.enable">enable</link> = true;
|
||||||
<link linkend="opt-services.sourcehut.originBase">originBase</link> = fqdn;
|
<link linkend="opt-services.sourcehut.git.enable">git.enable</link> = true;
|
||||||
<link linkend="opt-services.sourcehut.services">services</link> = [ "meta" "man" "git" ];
|
<link linkend="opt-services.sourcehut.man.enable">man.enable</link> = true;
|
||||||
|
<link linkend="opt-services.sourcehut.meta.enable">meta.enable</link> = true;
|
||||||
|
<link linkend="opt-services.sourcehut.nginx.enable">nginx.enable</link> = true;
|
||||||
|
<link linkend="opt-services.sourcehut.postfix.enable">postfix.enable</link> = true;
|
||||||
|
<link linkend="opt-services.sourcehut.postgresql.enable">postgresql.enable</link> = true;
|
||||||
|
<link linkend="opt-services.sourcehut.redis.enable">redis.enable</link> = true;
|
||||||
<link linkend="opt-services.sourcehut.settings">settings</link> = {
|
<link linkend="opt-services.sourcehut.settings">settings</link> = {
|
||||||
"sr.ht" = {
|
"sr.ht" = {
|
||||||
environment = "production";
|
environment = "production";
|
||||||
global-domain = fqdn;
|
global-domain = fqdn;
|
||||||
origin = "https://${fqdn}";
|
origin = "https://${fqdn}";
|
||||||
# Produce keys with srht-keygen from <package>sourcehut.coresrht</package>.
|
# Produce keys with srht-keygen from <package>sourcehut.coresrht</package>.
|
||||||
network-key = "SECRET";
|
network-key = "/run/keys/path/to/network-key";
|
||||||
service-key = "SECRET";
|
service-key = "/run/keys/path/to/service-key";
|
||||||
};
|
};
|
||||||
webhooks.private-key= "SECRET";
|
webhooks.private-key= "/run/keys/path/to/webhook-key";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -236,6 +236,7 @@ in
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
KEA_PIDFILE_DIR = "/run/kea";
|
KEA_PIDFILE_DIR = "/run/kea";
|
||||||
|
KEA_LOCKFILE_DIR = "/run/kea";
|
||||||
};
|
};
|
||||||
|
|
||||||
restartTriggers = [
|
restartTriggers = [
|
||||||
|
@ -271,6 +272,7 @@ in
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
KEA_PIDFILE_DIR = "/run/kea";
|
KEA_PIDFILE_DIR = "/run/kea";
|
||||||
|
KEA_LOCKFILE_DIR = "/run/kea";
|
||||||
};
|
};
|
||||||
|
|
||||||
restartTriggers = [
|
restartTriggers = [
|
||||||
|
@ -313,6 +315,7 @@ in
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
KEA_PIDFILE_DIR = "/run/kea";
|
KEA_PIDFILE_DIR = "/run/kea";
|
||||||
|
KEA_LOCKFILE_DIR = "/run/kea";
|
||||||
};
|
};
|
||||||
|
|
||||||
restartTriggers = [
|
restartTriggers = [
|
||||||
|
@ -353,6 +356,7 @@ in
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
KEA_PIDFILE_DIR = "/run/kea";
|
KEA_PIDFILE_DIR = "/run/kea";
|
||||||
|
KEA_LOCKFILE_DIR = "/run/kea";
|
||||||
};
|
};
|
||||||
|
|
||||||
restartTriggers = [
|
restartTriggers = [
|
||||||
|
@ -361,7 +365,7 @@ in
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${package}/bin/kea-dhcp-ddns -c /etc/kea/dhcp-ddns.conf ${lib.escapeShellArgs cfg.dhcp-ddns.extraArgs}";
|
ExecStart = "${package}/bin/kea-dhcp-ddns -c /etc/kea/dhcp-ddns.conf ${lib.escapeShellArgs cfg.dhcp-ddns.extraArgs}";
|
||||||
AmbientCapabilites = [
|
AmbientCapabilities = [
|
||||||
"CAP_NET_BIND_SERVICE"
|
"CAP_NET_BIND_SERVICE"
|
||||||
];
|
];
|
||||||
CapabilityBoundingSet = [
|
CapabilityBoundingSet = [
|
||||||
|
|
|
@ -72,7 +72,7 @@ services.prosody = {
|
||||||
a TLS certificate for the three endponits:
|
a TLS certificate for the three endponits:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
security.acme = {
|
security.acme = {
|
||||||
<link linkend="opt-security.acme.email">email</link> = "root@example.org";
|
<link linkend="opt-security.acme.defaults.email">email</link> = "root@example.org";
|
||||||
<link linkend="opt-security.acme.acceptTerms">acceptTerms</link> = true;
|
<link linkend="opt-security.acme.acceptTerms">acceptTerms</link> = true;
|
||||||
<link linkend="opt-security.acme.certs">certs</link> = {
|
<link linkend="opt-security.acme.certs">certs</link> = {
|
||||||
"example.org" = {
|
"example.org" = {
|
||||||
|
|
|
@ -25,7 +25,7 @@ services.discourse = {
|
||||||
};
|
};
|
||||||
<link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file";
|
<link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file";
|
||||||
};
|
};
|
||||||
<link linkend="opt-security.acme.email">security.acme.email</link> = "me@example.com";
|
<link linkend="opt-security.acme.defaults.email">security.acme.email</link> = "me@example.com";
|
||||||
<link linkend="opt-security.acme.acceptTerms">security.acme.acceptTerms</link> = true;
|
<link linkend="opt-security.acme.acceptTerms">security.acme.acceptTerms</link> = true;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
};
|
};
|
||||||
<link linkend="opt-services.jitsi-videobridge.openFirewall">services.jitsi-videobridge.openFirewall</link> = true;
|
<link linkend="opt-services.jitsi-videobridge.openFirewall">services.jitsi-videobridge.openFirewall</link> = true;
|
||||||
<link linkend="opt-networking.firewall.allowedTCPPorts">networking.firewall.allowedTCPPorts</link> = [ 80 443 ];
|
<link linkend="opt-networking.firewall.allowedTCPPorts">networking.firewall.allowedTCPPorts</link> = [ 80 443 ];
|
||||||
<link linkend="opt-security.acme.email">security.acme.email</link> = "me@example.com";
|
<link linkend="opt-security.acme.defaults.email">security.acme.email</link> = "me@example.com";
|
||||||
<link linkend="opt-security.acme.acceptTerms">security.acme.acceptTerms</link> = true;
|
<link linkend="opt-security.acme.acceptTerms">security.acme.acceptTerms</link> = true;
|
||||||
}</programlisting>
|
}</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
};
|
};
|
||||||
<link linkend="opt-services.jitsi-videobridge.openFirewall">services.jitsi-videobridge.openFirewall</link> = true;
|
<link linkend="opt-services.jitsi-videobridge.openFirewall">services.jitsi-videobridge.openFirewall</link> = true;
|
||||||
<link linkend="opt-networking.firewall.allowedTCPPorts">networking.firewall.allowedTCPPorts</link> = [ 80 443 ];
|
<link linkend="opt-networking.firewall.allowedTCPPorts">networking.firewall.allowedTCPPorts</link> = [ 80 443 ];
|
||||||
<link linkend="opt-security.acme.email">security.acme.email</link> = "me@example.com";
|
<link linkend="opt-security.acme.defaults.email">security.acme.email</link> = "me@example.com";
|
||||||
<link linkend="opt-security.acme.acceptTerms">security.acme.acceptTerms</link> = true;
|
<link linkend="opt-security.acme.acceptTerms">security.acme.acceptTerms</link> = true;
|
||||||
}</programlisting>
|
}</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
|
@ -154,7 +154,7 @@ let
|
||||||
sslServerKey = if useACME then "${sslCertDir}/key.pem" else hostOpts.sslServerKey;
|
sslServerKey = if useACME then "${sslCertDir}/key.pem" else hostOpts.sslServerKey;
|
||||||
sslServerChain = if useACME then "${sslCertDir}/chain.pem" else hostOpts.sslServerChain;
|
sslServerChain = if useACME then "${sslCertDir}/chain.pem" else hostOpts.sslServerChain;
|
||||||
|
|
||||||
acmeChallenge = optionalString useACME ''
|
acmeChallenge = optionalString (useACME && hostOpts.acmeRoot != null) ''
|
||||||
Alias /.well-known/acme-challenge/ "${hostOpts.acmeRoot}/.well-known/acme-challenge/"
|
Alias /.well-known/acme-challenge/ "${hostOpts.acmeRoot}/.well-known/acme-challenge/"
|
||||||
<Directory "${hostOpts.acmeRoot}">
|
<Directory "${hostOpts.acmeRoot}">
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
|
@ -677,9 +677,16 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
security.acme.certs = let
|
security.acme.certs = let
|
||||||
acmePairs = map (hostOpts: nameValuePair hostOpts.hostName {
|
acmePairs = map (hostOpts: let
|
||||||
|
hasRoot = hostOpts.acmeRoot != null;
|
||||||
|
in nameValuePair hostOpts.hostName {
|
||||||
group = mkDefault cfg.group;
|
group = mkDefault cfg.group;
|
||||||
webroot = hostOpts.acmeRoot;
|
# if acmeRoot is null inherit config.security.acme
|
||||||
|
# Since config.security.acme.certs.<cert>.webroot's own default value
|
||||||
|
# should take precedence set priority higher than mkOptionDefault
|
||||||
|
webroot = mkOverride (if hasRoot then 1000 else 2000) hostOpts.acmeRoot;
|
||||||
|
# Also nudge dnsProvider to null in case it is inherited
|
||||||
|
dnsProvider = mkOverride (if hasRoot then 1000 else 2000) null;
|
||||||
extraDomainNames = hostOpts.serverAliases;
|
extraDomainNames = hostOpts.serverAliases;
|
||||||
# Use the vhost-specific email address if provided, otherwise let
|
# Use the vhost-specific email address if provided, otherwise let
|
||||||
# security.acme.email or security.acme.certs.<cert>.email be used.
|
# security.acme.email or security.acme.certs.<cert>.email be used.
|
||||||
|
|
|
@ -128,9 +128,12 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
acmeRoot = mkOption {
|
acmeRoot = mkOption {
|
||||||
type = types.str;
|
type = types.nullOr types.str;
|
||||||
default = "/var/lib/acme/acme-challenge";
|
default = "/var/lib/acme/acme-challenge";
|
||||||
description = "Directory for the acme challenge which is PUBLIC, don't put certs or keys in here";
|
description = ''
|
||||||
|
Directory for the acme challenge which is PUBLIC, don't put certs or keys in here.
|
||||||
|
Set to null to inherit from config.security.acme.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
sslServerCert = mkOption {
|
sslServerCert = mkOption {
|
||||||
|
|
|
@ -278,7 +278,7 @@ let
|
||||||
acmeLocation = optionalString (vhost.enableACME || vhost.useACMEHost != null) ''
|
acmeLocation = optionalString (vhost.enableACME || vhost.useACMEHost != null) ''
|
||||||
location /.well-known/acme-challenge {
|
location /.well-known/acme-challenge {
|
||||||
${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"}
|
${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"}
|
||||||
root ${vhost.acmeRoot};
|
${optionalString (vhost.acmeRoot != null) "root ${vhost.acmeRoot};"}
|
||||||
auth_basic off;
|
auth_basic off;
|
||||||
}
|
}
|
||||||
${optionalString (vhost.acmeFallbackHost != null) ''
|
${optionalString (vhost.acmeFallbackHost != null) ''
|
||||||
|
@ -948,9 +948,16 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
security.acme.certs = let
|
security.acme.certs = let
|
||||||
acmePairs = map (vhostConfig: nameValuePair vhostConfig.serverName {
|
acmePairs = map (vhostConfig: let
|
||||||
|
hasRoot = vhostConfig.acmeRoot != null;
|
||||||
|
in nameValuePair vhostConfig.serverName {
|
||||||
group = mkDefault cfg.group;
|
group = mkDefault cfg.group;
|
||||||
webroot = vhostConfig.acmeRoot;
|
# if acmeRoot is null inherit config.security.acme
|
||||||
|
# Since config.security.acme.certs.<cert>.webroot's own default value
|
||||||
|
# should take precedence set priority higher than mkOptionDefault
|
||||||
|
webroot = mkOverride (if hasRoot then 1000 else 2000) vhostConfig.acmeRoot;
|
||||||
|
# Also nudge dnsProvider to null in case it is inherited
|
||||||
|
dnsProvider = mkOverride (if hasRoot then 1000 else 2000) null;
|
||||||
extraDomainNames = vhostConfig.serverAliases;
|
extraDomainNames = vhostConfig.serverAliases;
|
||||||
# Filter for enableACME-only vhosts. Don't want to create dud certs
|
# Filter for enableACME-only vhosts. Don't want to create dud certs
|
||||||
}) (filter (vhostConfig: vhostConfig.useACMEHost == null) acmeEnabledVhosts);
|
}) (filter (vhostConfig: vhostConfig.useACMEHost == null) acmeEnabledVhosts);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# has additional options that affect the web server as a whole, like
|
# has additional options that affect the web server as a whole, like
|
||||||
# the user/group to run under.)
|
# the user/group to run under.)
|
||||||
|
|
||||||
{ lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
{
|
{
|
||||||
|
@ -85,9 +85,12 @@ with lib;
|
||||||
};
|
};
|
||||||
|
|
||||||
acmeRoot = mkOption {
|
acmeRoot = mkOption {
|
||||||
type = types.str;
|
type = types.nullOr types.str;
|
||||||
default = "/var/lib/acme/acme-challenge";
|
default = "/var/lib/acme/acme-challenge";
|
||||||
description = "Directory for the acme challenge which is PUBLIC, don't put certs or keys in here";
|
description = ''
|
||||||
|
Directory for the acme challenge which is PUBLIC, don't put certs or keys in here.
|
||||||
|
Set to null to inherit from config.security.acme.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
acmeFallbackHost = mkOption {
|
acmeFallbackHost = mkOption {
|
||||||
|
|
|
@ -263,15 +263,6 @@ if test -n "$debug1devices"; then fail; fi
|
||||||
@postDeviceCommands@
|
@postDeviceCommands@
|
||||||
|
|
||||||
|
|
||||||
# Return true if the machine is on AC power, or if we can't determine
|
|
||||||
# whether it's on AC power.
|
|
||||||
onACPower() {
|
|
||||||
! test -d "/proc/acpi/battery" ||
|
|
||||||
! ls /proc/acpi/battery/BAT[0-9]* > /dev/null 2>&1 ||
|
|
||||||
! cat /proc/acpi/battery/BAT*/state | grep "^charging state" | grep -q "discharg"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Check the specified file system, if appropriate.
|
# Check the specified file system, if appropriate.
|
||||||
checkFS() {
|
checkFS() {
|
||||||
local device="$1"
|
local device="$1"
|
||||||
|
@ -316,13 +307,6 @@ checkFS() {
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Don't run `fsck' if the machine is on battery power. !!! Is
|
|
||||||
# this a good idea?
|
|
||||||
if ! onACPower; then
|
|
||||||
echo "on battery power, so no \`fsck' will be performed on \`$device'"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "checking $device..."
|
echo "checking $device..."
|
||||||
|
|
||||||
fsckFlags=
|
fsckFlags=
|
||||||
|
|
98
third_party/nixpkgs/nixos/modules/virtualisation/docker-rootless.nix
vendored
Normal file
98
third_party/nixpkgs/nixos/modules/virtualisation/docker-rootless.nix
vendored
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
cfg = config.virtualisation.docker.rootless;
|
||||||
|
proxy_env = config.networking.proxy.envVars;
|
||||||
|
settingsFormat = pkgs.formats.json {};
|
||||||
|
daemonSettingsFile = settingsFormat.generate "daemon.json" cfg.daemon.settings;
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
###### interface
|
||||||
|
|
||||||
|
options.virtualisation.docker.rootless = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
This option enables docker in a rootless mode, a daemon that manages
|
||||||
|
linux containers. To interact with the daemon, one needs to set
|
||||||
|
<command>DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock</command>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
setSocketVariable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Point <command>DOCKER_HOST</command> to rootless Docker instance for
|
||||||
|
normal users by default.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
daemon.settings = mkOption {
|
||||||
|
type = settingsFormat.type;
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
ipv6 = true;
|
||||||
|
"fixed-cidr-v6" = "fd00::/80";
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
Configuration for docker daemon. The attributes are serialized to JSON used as daemon.conf.
|
||||||
|
See https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
default = pkgs.docker;
|
||||||
|
defaultText = literalExpression "pkgs.docker";
|
||||||
|
type = types.package;
|
||||||
|
example = literalExpression "pkgs.docker-edge";
|
||||||
|
description = ''
|
||||||
|
Docker package to be used in the module.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
###### implementation
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
environment.systemPackages = [ cfg.package ];
|
||||||
|
|
||||||
|
environment.extraInit = optionalString cfg.setSocketVariable ''
|
||||||
|
if [ -z "$DOCKER_HOST" -a -n "$XDG_RUNTIME_DIR" ]; then
|
||||||
|
export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Taken from https://github.com/moby/moby/blob/master/contrib/dockerd-rootless-setuptool.sh
|
||||||
|
systemd.user.services.docker = {
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
description = "Docker Application Container Engine (Rootless)";
|
||||||
|
# needs newuidmap from pkgs.shadow
|
||||||
|
path = [ "/run/wrappers" ];
|
||||||
|
environment = proxy_env;
|
||||||
|
unitConfig.StartLimitInterval = "60s";
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "notify";
|
||||||
|
ExecStart = "${cfg.package}/bin/dockerd-rootless --config-file=${daemonSettingsFile}";
|
||||||
|
ExecReload = "${pkgs.procps}/bin/kill -s HUP $MAINPID";
|
||||||
|
TimeoutSec = 0;
|
||||||
|
RestartSec = 2;
|
||||||
|
Restart = "always";
|
||||||
|
StartLimitBurst = 3;
|
||||||
|
LimitNOFILE = "infinity";
|
||||||
|
LimitNPROC = "infinity";
|
||||||
|
LimitCORE = "infinity";
|
||||||
|
Delegate = true;
|
||||||
|
NotifyAccess = "all";
|
||||||
|
KillMode = "mixed";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
508
third_party/nixpkgs/nixos/tests/acme.nix
vendored
508
third_party/nixpkgs/nixos/tests/acme.nix
vendored
|
@ -1,9 +1,9 @@
|
||||||
let
|
import ./make-test-python.nix ({ pkgs, lib, ... }: let
|
||||||
commonConfig = ./common/acme/client;
|
commonConfig = ./common/acme/client;
|
||||||
|
|
||||||
dnsServerIP = nodes: nodes.dnsserver.config.networking.primaryIPAddress;
|
dnsServerIP = nodes: nodes.dnsserver.config.networking.primaryIPAddress;
|
||||||
|
|
||||||
dnsScript = {pkgs, nodes}: let
|
dnsScript = nodes: let
|
||||||
dnsAddress = dnsServerIP nodes;
|
dnsAddress = dnsServerIP nodes;
|
||||||
in pkgs.writeShellScript "dns-hook.sh" ''
|
in pkgs.writeShellScript "dns-hook.sh" ''
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
@ -15,30 +15,137 @@ let
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
documentRoot = pkgs: pkgs.runCommand "docroot" {} ''
|
dnsConfig = nodes: {
|
||||||
|
dnsProvider = "exec";
|
||||||
|
dnsPropagationCheck = false;
|
||||||
|
credentialsFile = pkgs.writeText "wildcard.env" ''
|
||||||
|
EXEC_PATH=${dnsScript nodes}
|
||||||
|
EXEC_POLLING_INTERVAL=1
|
||||||
|
EXEC_PROPAGATION_TIMEOUT=1
|
||||||
|
EXEC_SEQUENCE_INTERVAL=1
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
documentRoot = pkgs.runCommand "docroot" {} ''
|
||||||
mkdir -p "$out"
|
mkdir -p "$out"
|
||||||
echo hello world > "$out/index.html"
|
echo hello world > "$out/index.html"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
vhostBase = pkgs: {
|
vhostBase = {
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
locations."/".root = documentRoot pkgs;
|
locations."/".root = documentRoot;
|
||||||
};
|
};
|
||||||
|
|
||||||
in import ./make-test-python.nix ({ lib, ... }: {
|
vhostBaseHttpd = {
|
||||||
|
forceSSL = true;
|
||||||
|
inherit documentRoot;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Base specialisation config for testing general ACME features
|
||||||
|
webserverBasicConfig = {
|
||||||
|
services.nginx.enable = true;
|
||||||
|
services.nginx.virtualHosts."a.example.test" = vhostBase // {
|
||||||
|
enableACME = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Generate specialisations for testing a web server
|
||||||
|
mkServerConfigs = { server, group, vhostBaseData, extraConfig ? {} }: let
|
||||||
|
baseConfig = { nodes, config, specialConfig ? {} }: lib.mkMerge [
|
||||||
|
{
|
||||||
|
security.acme = {
|
||||||
|
defaults = (dnsConfig nodes) // {
|
||||||
|
inherit group;
|
||||||
|
};
|
||||||
|
# One manual wildcard cert
|
||||||
|
certs."example.test" = {
|
||||||
|
domain = "*.example.test";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services."${server}" = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts = {
|
||||||
|
# Run-of-the-mill vhost using HTTP-01 validation
|
||||||
|
"${server}-http.example.test" = vhostBaseData // {
|
||||||
|
serverAliases = [ "${server}-http-alias.example.test" ];
|
||||||
|
enableACME = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Another which inherits the DNS-01 config
|
||||||
|
"${server}-dns.example.test" = vhostBaseData // {
|
||||||
|
serverAliases = [ "${server}-dns-alias.example.test" ];
|
||||||
|
enableACME = true;
|
||||||
|
# Set acmeRoot to null instead of using the default of "/var/lib/acme/acme-challenge"
|
||||||
|
# webroot + dnsProvider are mutually exclusive.
|
||||||
|
acmeRoot = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
# One using the wildcard certificate
|
||||||
|
"${server}-wildcard.example.test" = vhostBaseData // {
|
||||||
|
serverAliases = [ "${server}-wildcard-alias.example.test" ];
|
||||||
|
useACMEHost = "example.test";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Used to determine if service reload was triggered
|
||||||
|
systemd.targets."test-renew-${server}" = {
|
||||||
|
wants = [ "acme-${server}-http.example.test.service" ];
|
||||||
|
after = [ "acme-${server}-http.example.test.service" "${server}-config-reload.service" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
specialConfig
|
||||||
|
extraConfig
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
"${server}".configuration = { nodes, config, ... }: baseConfig {
|
||||||
|
inherit nodes config;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Test that server reloads when an alias is removed (and subsequently test removal works in acme)
|
||||||
|
"${server}-remove-alias".configuration = { nodes, config, ... }: baseConfig {
|
||||||
|
inherit nodes config;
|
||||||
|
specialConfig = {
|
||||||
|
# Remove an alias, but create a standalone vhost in its place for testing.
|
||||||
|
# This configuration results in certificate errors as useACMEHost does not imply
|
||||||
|
# append extraDomains, and thus we can validate the SAN is removed.
|
||||||
|
services."${server}" = {
|
||||||
|
virtualHosts."${server}-http.example.test".serverAliases = lib.mkForce [];
|
||||||
|
virtualHosts."${server}-http-alias.example.test" = vhostBaseData // {
|
||||||
|
useACMEHost = "${server}-http.example.test";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Test that the server reloads when only the acme configuration is changed.
|
||||||
|
"${server}-change-acme-conf".configuration = { nodes, config, ... }: baseConfig {
|
||||||
|
inherit nodes config;
|
||||||
|
specialConfig = {
|
||||||
|
security.acme.certs."${server}-http.example.test" = {
|
||||||
|
keyType = "ec384";
|
||||||
|
# Also test that postRun is exec'd as root
|
||||||
|
postRun = "id | grep root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
name = "acme";
|
name = "acme";
|
||||||
meta.maintainers = lib.teams.acme.members;
|
meta.maintainers = lib.teams.acme.members;
|
||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
# The fake ACME server which will respond to client requests
|
# The fake ACME server which will respond to client requests
|
||||||
acme = { nodes, lib, ... }: {
|
acme = { nodes, ... }: {
|
||||||
imports = [ ./common/acme/server ];
|
imports = [ ./common/acme/server ];
|
||||||
networking.nameservers = lib.mkForce [ (dnsServerIP nodes) ];
|
networking.nameservers = lib.mkForce [ (dnsServerIP nodes) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# A fake DNS server which can be configured with records as desired
|
# A fake DNS server which can be configured with records as desired
|
||||||
# Used to test DNS-01 challenge
|
# Used to test DNS-01 challenge
|
||||||
dnsserver = { nodes, pkgs, ... }: {
|
dnsserver = { nodes, ... }: {
|
||||||
networking.firewall.allowedTCPPorts = [ 8055 53 ];
|
networking.firewall.allowedTCPPorts = [ 8055 53 ];
|
||||||
networking.firewall.allowedUDPPorts = [ 53 ];
|
networking.firewall.allowedUDPPorts = [ 53 ];
|
||||||
systemd.services.pebble-challtestsrv = {
|
systemd.services.pebble-challtestsrv = {
|
||||||
|
@ -54,7 +161,7 @@ in import ./make-test-python.nix ({ lib, ... }: {
|
||||||
};
|
};
|
||||||
|
|
||||||
# A web server which will be the node requesting certs
|
# A web server which will be the node requesting certs
|
||||||
webserver = { pkgs, nodes, lib, config, ... }: {
|
webserver = { nodes, config, ... }: {
|
||||||
imports = [ commonConfig ];
|
imports = [ commonConfig ];
|
||||||
networking.nameservers = lib.mkForce [ (dnsServerIP nodes) ];
|
networking.nameservers = lib.mkForce [ (dnsServerIP nodes) ];
|
||||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||||
|
@ -63,113 +170,53 @@ in import ./make-test-python.nix ({ lib, ... }: {
|
||||||
environment.systemPackages = [ pkgs.openssl ];
|
environment.systemPackages = [ pkgs.openssl ];
|
||||||
|
|
||||||
# Set log level to info so that we can see when the service is reloaded
|
# Set log level to info so that we can see when the service is reloaded
|
||||||
services.nginx.enable = true;
|
|
||||||
services.nginx.logError = "stderr info";
|
services.nginx.logError = "stderr info";
|
||||||
|
|
||||||
# First tests configure a basic cert and run a bunch of openssl checks
|
specialisation = {
|
||||||
services.nginx.virtualHosts."a.example.test" = (vhostBase pkgs) // {
|
# First derivation used to test general ACME features
|
||||||
enableACME = true;
|
general.configuration = { ... }: let
|
||||||
};
|
|
||||||
|
|
||||||
# Used to determine if service reload was triggered
|
|
||||||
systemd.targets.test-renew-nginx = {
|
|
||||||
wants = [ "acme-a.example.test.service" ];
|
|
||||||
after = [ "acme-a.example.test.service" "nginx-config-reload.service" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# Test that account creation is collated into one service
|
|
||||||
specialisation.account-creation.configuration = { nodes, pkgs, lib, ... }: let
|
|
||||||
email = "newhostmaster@example.test";
|
|
||||||
caDomain = nodes.acme.config.test-support.acme.caDomain;
|
caDomain = nodes.acme.config.test-support.acme.caDomain;
|
||||||
|
email = config.security.acme.defaults.email;
|
||||||
# Exit 99 to make it easier to track if this is the reason a renew failed
|
# Exit 99 to make it easier to track if this is the reason a renew failed
|
||||||
testScript = ''
|
accountCreateTester = ''
|
||||||
test -e accounts/${caDomain}/${email}/account.json || exit 99
|
test -e accounts/${caDomain}/${email}/account.json || exit 99
|
||||||
'';
|
'';
|
||||||
in {
|
in lib.mkMerge [
|
||||||
security.acme.email = lib.mkForce email;
|
webserverBasicConfig
|
||||||
systemd.services."b.example.test".preStart = testScript;
|
{
|
||||||
systemd.services."c.example.test".preStart = testScript;
|
# Used to test that account creation is collated into one service.
|
||||||
|
# These should not run until after acme-finished-a.example.test.target
|
||||||
|
systemd.services."b.example.test".preStart = accountCreateTester;
|
||||||
|
systemd.services."c.example.test".preStart = accountCreateTester;
|
||||||
|
|
||||||
services.nginx.virtualHosts."b.example.test" = (vhostBase pkgs) // {
|
services.nginx.virtualHosts."b.example.test" = vhostBase // {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
};
|
};
|
||||||
services.nginx.virtualHosts."c.example.test" = (vhostBase pkgs) // {
|
services.nginx.virtualHosts."c.example.test" = vhostBase // {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
];
|
||||||
# Cert config changes will not cause the nginx configuration to change.
|
|
||||||
# This tests that the reload service is correctly triggered.
|
|
||||||
# It also tests that postRun is exec'd as root
|
|
||||||
specialisation.cert-change.configuration = { pkgs, ... }: {
|
|
||||||
security.acme.certs."a.example.test".keyType = "ec384";
|
|
||||||
security.acme.certs."a.example.test".postRun = ''
|
|
||||||
set -euo pipefail
|
|
||||||
touch /home/test
|
|
||||||
chown root:root /home/test
|
|
||||||
echo testing > /home/test
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# Now adding an alias to ensure that the certs are updated
|
|
||||||
specialisation.nginx-aliases.configuration = { pkgs, ... }: {
|
|
||||||
services.nginx.virtualHosts."a.example.test" = {
|
|
||||||
serverAliases = [ "b.example.test" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Test OCSP Stapling
|
# Test OCSP Stapling
|
||||||
specialisation.ocsp-stapling.configuration = { pkgs, ... }: {
|
ocsp-stapling.configuration = { ... }: lib.mkMerge [
|
||||||
security.acme.certs."a.example.test" = {
|
webserverBasicConfig
|
||||||
ocspMustStaple = true;
|
{
|
||||||
};
|
security.acme.certs."a.example.test".ocspMustStaple = true;
|
||||||
services.nginx.virtualHosts."a.example.com" = {
|
services.nginx.virtualHosts."a.example.test" = {
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
ssl_stapling on;
|
ssl_stapling on;
|
||||||
ssl_stapling_verify on;
|
ssl_stapling_verify on;
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
];
|
||||||
# Test using Apache HTTPD
|
|
||||||
specialisation.httpd-aliases.configuration = { pkgs, config, lib, ... }: {
|
|
||||||
services.nginx.enable = lib.mkForce false;
|
|
||||||
services.httpd.enable = true;
|
|
||||||
services.httpd.adminAddr = config.security.acme.email;
|
|
||||||
services.httpd.virtualHosts."c.example.test" = {
|
|
||||||
serverAliases = [ "d.example.test" ];
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
documentRoot = documentRoot pkgs;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Used to determine if service reload was triggered
|
|
||||||
systemd.targets.test-renew-httpd = {
|
|
||||||
wants = [ "acme-c.example.test.service" ];
|
|
||||||
after = [ "acme-c.example.test.service" "httpd-config-reload.service" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Validation via DNS-01 challenge
|
|
||||||
specialisation.dns-01.configuration = { pkgs, config, nodes, ... }: {
|
|
||||||
security.acme.certs."example.test" = {
|
|
||||||
domain = "*.example.test";
|
|
||||||
group = config.services.nginx.group;
|
|
||||||
dnsProvider = "exec";
|
|
||||||
dnsPropagationCheck = false;
|
|
||||||
credentialsFile = pkgs.writeText "wildcard.env" ''
|
|
||||||
EXEC_PATH=${dnsScript { inherit pkgs nodes; }}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
services.nginx.virtualHosts."dns.example.test" = (vhostBase pkgs) // {
|
|
||||||
useACMEHost = "example.test";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Validate service relationships by adding a slow start service to nginx' wants.
|
# Validate service relationships by adding a slow start service to nginx' wants.
|
||||||
# Reproducer for https://github.com/NixOS/nixpkgs/issues/81842
|
# Reproducer for https://github.com/NixOS/nixpkgs/issues/81842
|
||||||
specialisation.slow-startup.configuration = { pkgs, config, nodes, lib, ... }: {
|
slow-startup.configuration = { ... }: lib.mkMerge [
|
||||||
|
webserverBasicConfig
|
||||||
|
{
|
||||||
systemd.services.my-slow-service = {
|
systemd.services.my-slow-service = {
|
||||||
wantedBy = [ "multi-user.target" "nginx.service" ];
|
wantedBy = [ "multi-user.target" "nginx.service" ];
|
||||||
before = [ "nginx.service" ];
|
before = [ "nginx.service" ];
|
||||||
|
@ -177,16 +224,88 @@ in import ./make-test-python.nix ({ lib, ... }: {
|
||||||
script = "${pkgs.python3}/bin/python -m http.server";
|
script = "${pkgs.python3}/bin/python -m http.server";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx.virtualHosts."slow.example.com" = {
|
services.nginx.virtualHosts."slow.example.test" = {
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
locations."/".proxyPass = "http://localhost:8000";
|
locations."/".proxyPass = "http://localhost:8000";
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Test lego internal server (listenHTTP option)
|
||||||
|
# Also tests useRoot option
|
||||||
|
lego-server.configuration = { ... }: {
|
||||||
|
security.acme.useRoot = true;
|
||||||
|
security.acme.certs."lego.example.test" = {
|
||||||
|
listenHTTP = ":80";
|
||||||
|
group = "nginx";
|
||||||
|
};
|
||||||
|
services.nginx.enable = true;
|
||||||
|
services.nginx.virtualHosts."lego.example.test" = {
|
||||||
|
useACMEHost = "lego.example.test";
|
||||||
|
onlySSL = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Test compatiblity with Caddy
|
||||||
|
# It only supports useACMEHost, hence not using mkServerConfigs
|
||||||
|
} // (let
|
||||||
|
baseCaddyConfig = { nodes, config, ... }: {
|
||||||
|
security.acme = {
|
||||||
|
defaults = (dnsConfig nodes) // {
|
||||||
|
group = config.services.caddy.group;
|
||||||
|
};
|
||||||
|
# One manual wildcard cert
|
||||||
|
certs."example.test" = {
|
||||||
|
domain = "*.example.test";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.caddy = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts."a.exmaple.test" = {
|
||||||
|
useACMEHost = "example.test";
|
||||||
|
extraConfig = ''
|
||||||
|
root * ${documentRoot}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
caddy.configuration = baseCaddyConfig;
|
||||||
|
|
||||||
|
# Test that the server reloads when only the acme configuration is changed.
|
||||||
|
"caddy-change-acme-conf".configuration = { nodes, config, ... }: lib.mkMerge [
|
||||||
|
(baseCaddyConfig {
|
||||||
|
inherit nodes config;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
security.acme.certs."example.test" = {
|
||||||
|
keyType = "ec384";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Test compatibility with Nginx
|
||||||
|
}) // (mkServerConfigs {
|
||||||
|
server = "nginx";
|
||||||
|
group = "nginx";
|
||||||
|
vhostBaseData = vhostBase;
|
||||||
|
})
|
||||||
|
|
||||||
|
# Test compatibility with Apache HTTPD
|
||||||
|
// (mkServerConfigs {
|
||||||
|
server = "httpd";
|
||||||
|
group = "wwwrun";
|
||||||
|
vhostBaseData = vhostBaseHttpd;
|
||||||
|
extraConfig = {
|
||||||
|
services.httpd.adminAddr = config.security.acme.defaults.email;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
# The client will be used to curl the webserver to validate configuration
|
# The client will be used to curl the webserver to validate configuration
|
||||||
client = {nodes, lib, pkgs, ...}: {
|
client = { nodes, ... }: {
|
||||||
imports = [ commonConfig ];
|
imports = [ commonConfig ];
|
||||||
networking.nameservers = lib.mkForce [ (dnsServerIP nodes) ];
|
networking.nameservers = lib.mkForce [ (dnsServerIP nodes) ];
|
||||||
|
|
||||||
|
@ -204,23 +323,26 @@ in import ./make-test-python.nix ({ lib, ... }: {
|
||||||
# Note, wait_for_unit does not work for oneshot services that do not have RemainAfterExit=true,
|
# Note, wait_for_unit does not work for oneshot services that do not have RemainAfterExit=true,
|
||||||
# this is because a oneshot goes from inactive => activating => inactive, and never
|
# this is because a oneshot goes from inactive => activating => inactive, and never
|
||||||
# reaches the active state. Targets do not have this issue.
|
# reaches the active state. Targets do not have this issue.
|
||||||
|
|
||||||
''
|
''
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
has_switched = False
|
|
||||||
|
|
||||||
|
|
||||||
def switch_to(node, name):
|
def switch_to(node, name):
|
||||||
global has_switched
|
# On first switch, this will create a symlink to the current system so that we can
|
||||||
if has_switched:
|
# quickly switch between derivations
|
||||||
node.succeed(
|
root_specs = "/tmp/specialisation"
|
||||||
"${switchToNewServer}"
|
node.execute(
|
||||||
|
f"test -e {root_specs}"
|
||||||
|
f" || ln -s $(readlink /run/current-system)/specialisation {root_specs}"
|
||||||
)
|
)
|
||||||
has_switched = True
|
|
||||||
|
switcher_path = f"/run/current-system/specialisation/{name}/bin/switch-to-configuration"
|
||||||
|
rc, _ = node.execute(f"test -e '{switcher_path}'")
|
||||||
|
if rc > 0:
|
||||||
|
switcher_path = f"/tmp/specialisation/{name}/bin/switch-to-configuration"
|
||||||
|
|
||||||
node.succeed(
|
node.succeed(
|
||||||
f"/run/current-system/specialisation/{name}/bin/switch-to-configuration test"
|
f"{switcher_path} test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -310,8 +432,7 @@ in import ./make-test-python.nix ({ lib, ... }: {
|
||||||
return download_ca_certs(node, retries - 1)
|
return download_ca_certs(node, retries - 1)
|
||||||
|
|
||||||
|
|
||||||
client.start()
|
start_all()
|
||||||
dnsserver.start()
|
|
||||||
|
|
||||||
dnsserver.wait_for_unit("pebble-challtestsrv.service")
|
dnsserver.wait_for_unit("pebble-challtestsrv.service")
|
||||||
client.wait_for_unit("default.target")
|
client.wait_for_unit("default.target")
|
||||||
|
@ -320,19 +441,30 @@ in import ./make-test-python.nix ({ lib, ... }: {
|
||||||
'curl --data \'{"host": "${caDomain}", "addresses": ["${nodes.acme.config.networking.primaryIPAddress}"]}\' http://${dnsServerIP nodes}:8055/add-a'
|
'curl --data \'{"host": "${caDomain}", "addresses": ["${nodes.acme.config.networking.primaryIPAddress}"]}\' http://${dnsServerIP nodes}:8055/add-a'
|
||||||
)
|
)
|
||||||
|
|
||||||
acme.start()
|
|
||||||
webserver.start()
|
|
||||||
|
|
||||||
acme.wait_for_unit("network-online.target")
|
acme.wait_for_unit("network-online.target")
|
||||||
acme.wait_for_unit("pebble.service")
|
acme.wait_for_unit("pebble.service")
|
||||||
|
|
||||||
download_ca_certs(client)
|
download_ca_certs(client)
|
||||||
|
|
||||||
with subtest("Can request certificate with HTTPS-01 challenge"):
|
# Perform general tests first
|
||||||
|
switch_to(webserver, "general")
|
||||||
|
|
||||||
|
with subtest("Can request certificate with HTTP-01 challenge"):
|
||||||
webserver.wait_for_unit("acme-finished-a.example.test.target")
|
webserver.wait_for_unit("acme-finished-a.example.test.target")
|
||||||
|
check_fullchain(webserver, "a.example.test")
|
||||||
|
check_issuer(webserver, "a.example.test", "pebble")
|
||||||
|
webserver.wait_for_unit("nginx.service")
|
||||||
|
check_connection(client, "a.example.test")
|
||||||
|
|
||||||
|
with subtest("Runs 1 cert for account creation before others"):
|
||||||
|
webserver.wait_for_unit("acme-finished-b.example.test.target")
|
||||||
|
webserver.wait_for_unit("acme-finished-c.example.test.target")
|
||||||
|
check_connection(client, "b.example.test")
|
||||||
|
check_connection(client, "c.example.test")
|
||||||
|
|
||||||
with subtest("Certificates and accounts have safe + valid permissions"):
|
with subtest("Certificates and accounts have safe + valid permissions"):
|
||||||
group = "${nodes.webserver.config.security.acme.certs."a.example.test".group}"
|
# Nginx will set the group appropriately when enableACME is used
|
||||||
|
group = "nginx"
|
||||||
webserver.succeed(
|
webserver.succeed(
|
||||||
f"test $(stat -L -c '%a %U %G' /var/lib/acme/a.example.test/*.pem | tee /dev/stderr | grep '640 acme {group}' | wc -l) -eq 5"
|
f"test $(stat -L -c '%a %U %G' /var/lib/acme/a.example.test/*.pem | tee /dev/stderr | grep '640 acme {group}' | wc -l) -eq 5"
|
||||||
)
|
)
|
||||||
|
@ -346,12 +478,6 @@ in import ./make-test-python.nix ({ lib, ... }: {
|
||||||
f"test $(find /var/lib/acme/accounts -type f -exec stat -L -c '%a %U %G' {{}} \\; | tee /dev/stderr | grep -v '600 acme {group}' | wc -l) -eq 0"
|
f"test $(find /var/lib/acme/accounts -type f -exec stat -L -c '%a %U %G' {{}} \\; | tee /dev/stderr | grep -v '600 acme {group}' | wc -l) -eq 0"
|
||||||
)
|
)
|
||||||
|
|
||||||
with subtest("Certs are accepted by web server"):
|
|
||||||
webserver.succeed("systemctl start nginx.service")
|
|
||||||
check_fullchain(webserver, "a.example.test")
|
|
||||||
check_issuer(webserver, "a.example.test", "pebble")
|
|
||||||
check_connection(client, "a.example.test")
|
|
||||||
|
|
||||||
# Selfsigned certs tests happen late so we aren't fighting the system init triggering cert renewal
|
# Selfsigned certs tests happen late so we aren't fighting the system init triggering cert renewal
|
||||||
with subtest("Can generate valid selfsigned certs"):
|
with subtest("Can generate valid selfsigned certs"):
|
||||||
webserver.succeed("systemctl clean acme-a.example.test.service --what=state")
|
webserver.succeed("systemctl clean acme-a.example.test.service --what=state")
|
||||||
|
@ -365,77 +491,107 @@ in import ./make-test-python.nix ({ lib, ... }: {
|
||||||
# Will succeed if nginx can load the certs
|
# Will succeed if nginx can load the certs
|
||||||
webserver.succeed("systemctl start nginx-config-reload.service")
|
webserver.succeed("systemctl start nginx-config-reload.service")
|
||||||
|
|
||||||
with subtest("Can reload nginx when timer triggers renewal"):
|
|
||||||
webserver.succeed("systemctl start test-renew-nginx.target")
|
|
||||||
check_issuer(webserver, "a.example.test", "pebble")
|
|
||||||
check_connection(client, "a.example.test")
|
|
||||||
|
|
||||||
with subtest("Runs 1 cert for account creation before others"):
|
|
||||||
switch_to(webserver, "account-creation")
|
|
||||||
webserver.wait_for_unit("acme-finished-a.example.test.target")
|
|
||||||
check_connection(client, "a.example.test")
|
|
||||||
webserver.wait_for_unit("acme-finished-b.example.test.target")
|
|
||||||
webserver.wait_for_unit("acme-finished-c.example.test.target")
|
|
||||||
check_connection(client, "b.example.test")
|
|
||||||
check_connection(client, "c.example.test")
|
|
||||||
|
|
||||||
with subtest("Can reload web server when cert configuration changes"):
|
|
||||||
switch_to(webserver, "cert-change")
|
|
||||||
webserver.wait_for_unit("acme-finished-a.example.test.target")
|
|
||||||
check_connection_key_bits(client, "a.example.test", "384")
|
|
||||||
webserver.succeed("grep testing /home/test")
|
|
||||||
# Clean to remove the testing file (and anything else messy we did)
|
|
||||||
webserver.succeed("systemctl clean acme-a.example.test.service --what=state")
|
|
||||||
|
|
||||||
with subtest("Correctly implements OCSP stapling"):
|
with subtest("Correctly implements OCSP stapling"):
|
||||||
switch_to(webserver, "ocsp-stapling")
|
switch_to(webserver, "ocsp-stapling")
|
||||||
webserver.wait_for_unit("acme-finished-a.example.test.target")
|
webserver.wait_for_unit("acme-finished-a.example.test.target")
|
||||||
check_stapling(client, "a.example.test")
|
check_stapling(client, "a.example.test")
|
||||||
|
|
||||||
with subtest("Can request certificate with HTTPS-01 when nginx startup is delayed"):
|
with subtest("Can request certificate with HTTP-01 using lego's internal web server"):
|
||||||
switch_to(webserver, "slow-startup")
|
switch_to(webserver, "lego-server")
|
||||||
webserver.wait_for_unit("acme-finished-slow.example.com.target")
|
webserver.wait_for_unit("acme-finished-lego.example.test.target")
|
||||||
check_issuer(webserver, "slow.example.com", "pebble")
|
webserver.wait_for_unit("nginx.service")
|
||||||
check_connection(client, "slow.example.com")
|
webserver.succeed("echo HENLO && systemctl cat nginx.service")
|
||||||
|
webserver.succeed("test \"$(stat -c '%U' /var/lib/acme/* | uniq)\" = \"root\"")
|
||||||
with subtest("Can request certificate for vhost + aliases (nginx)"):
|
|
||||||
# Check the key hash before and after adding an alias. It should not change.
|
|
||||||
# The previous test reverts the ed384 change
|
|
||||||
webserver.wait_for_unit("acme-finished-a.example.test.target")
|
|
||||||
switch_to(webserver, "nginx-aliases")
|
|
||||||
webserver.wait_for_unit("acme-finished-a.example.test.target")
|
|
||||||
check_issuer(webserver, "a.example.test", "pebble")
|
|
||||||
check_connection(client, "a.example.test")
|
check_connection(client, "a.example.test")
|
||||||
check_connection(client, "b.example.test")
|
check_connection(client, "lego.example.test")
|
||||||
|
|
||||||
with subtest("Can request certificates for vhost + aliases (apache-httpd)"):
|
with subtest("Can request certificate with HTTP-01 when nginx startup is delayed"):
|
||||||
|
webserver.execute("systemctl stop nginx")
|
||||||
|
switch_to(webserver, "slow-startup")
|
||||||
|
webserver.wait_for_unit("acme-finished-slow.example.test.target")
|
||||||
|
check_issuer(webserver, "slow.example.test", "pebble")
|
||||||
|
webserver.wait_for_unit("nginx.service")
|
||||||
|
check_connection(client, "slow.example.test")
|
||||||
|
|
||||||
|
with subtest("Works with caddy"):
|
||||||
|
switch_to(webserver, "caddy")
|
||||||
|
webserver.wait_for_unit("acme-finished-example.test.target")
|
||||||
|
webserver.wait_for_unit("caddy.service")
|
||||||
|
# FIXME reloading caddy is not sufficient to load new certs.
|
||||||
|
# Restart it manually until this is fixed.
|
||||||
|
webserver.succeed("systemctl restart caddy.service")
|
||||||
|
check_connection(client, "a.example.test")
|
||||||
|
|
||||||
|
with subtest("security.acme changes reflect on caddy"):
|
||||||
|
switch_to(webserver, "caddy-change-acme-conf")
|
||||||
|
webserver.wait_for_unit("acme-finished-example.test.target")
|
||||||
|
webserver.wait_for_unit("caddy.service")
|
||||||
|
# FIXME reloading caddy is not sufficient to load new certs.
|
||||||
|
# Restart it manually until this is fixed.
|
||||||
|
webserver.succeed("systemctl restart caddy.service")
|
||||||
|
check_connection_key_bits(client, "a.example.test", "384")
|
||||||
|
|
||||||
|
domains = ["http", "dns", "wildcard"]
|
||||||
|
for server, logsrc in [
|
||||||
|
("nginx", "journalctl -n 30 -u nginx.service"),
|
||||||
|
("httpd", "tail -n 30 /var/log/httpd/*.log"),
|
||||||
|
]:
|
||||||
|
wait_for_server = lambda: webserver.wait_for_unit(f"{server}.service")
|
||||||
|
with subtest(f"Works with {server}"):
|
||||||
try:
|
try:
|
||||||
switch_to(webserver, "httpd-aliases")
|
switch_to(webserver, server)
|
||||||
webserver.wait_for_unit("acme-finished-c.example.test.target")
|
# Skip wildcard domain for this check ([:-1])
|
||||||
|
for domain in domains[:-1]:
|
||||||
|
webserver.wait_for_unit(
|
||||||
|
f"acme-finished-{server}-{domain}.example.test.target"
|
||||||
|
)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
_, output = webserver.execute(
|
_, output = webserver.execute(
|
||||||
"cat /var/log/httpd/*.log && ls -al /var/lib/acme/acme-challenge"
|
f"{logsrc} && ls -al /var/lib/acme/acme-challenge"
|
||||||
)
|
)
|
||||||
print(output)
|
print(output)
|
||||||
raise err
|
raise err
|
||||||
check_issuer(webserver, "c.example.test", "pebble")
|
|
||||||
check_connection(client, "c.example.test")
|
|
||||||
check_connection(client, "d.example.test")
|
|
||||||
|
|
||||||
with subtest("Can reload httpd when timer triggers renewal"):
|
wait_for_server()
|
||||||
|
|
||||||
|
for domain in domains[:-1]:
|
||||||
|
check_issuer(webserver, f"{server}-{domain}.example.test", "pebble")
|
||||||
|
for domain in domains:
|
||||||
|
check_connection(client, f"{server}-{domain}.example.test")
|
||||||
|
check_connection(client, f"{server}-{domain}-alias.example.test")
|
||||||
|
|
||||||
|
test_domain = f"{server}-{domains[0]}.example.test"
|
||||||
|
|
||||||
|
with subtest(f"Can reload {server} when timer triggers renewal"):
|
||||||
# Switch to selfsigned first
|
# Switch to selfsigned first
|
||||||
webserver.succeed("systemctl clean acme-c.example.test.service --what=state")
|
webserver.succeed(f"systemctl clean acme-{test_domain}.service --what=state")
|
||||||
webserver.succeed("systemctl start acme-selfsigned-c.example.test.service")
|
webserver.succeed(f"systemctl start acme-selfsigned-{test_domain}.service")
|
||||||
check_issuer(webserver, "c.example.test", "minica")
|
check_issuer(webserver, test_domain, "minica")
|
||||||
webserver.succeed("systemctl start httpd-config-reload.service")
|
webserver.succeed(f"systemctl start {server}-config-reload.service")
|
||||||
webserver.succeed("systemctl start test-renew-httpd.target")
|
webserver.succeed(f"systemctl start test-renew-{server}.target")
|
||||||
check_issuer(webserver, "c.example.test", "pebble")
|
check_issuer(webserver, test_domain, "pebble")
|
||||||
check_connection(client, "c.example.test")
|
check_connection(client, test_domain)
|
||||||
|
|
||||||
with subtest("Can request wildcard certificates using DNS-01 challenge"):
|
with subtest("Can remove an alias from a domain + cert is updated"):
|
||||||
switch_to(webserver, "dns-01")
|
test_alias = f"{server}-{domains[0]}-alias.example.test"
|
||||||
webserver.wait_for_unit("acme-finished-example.test.target")
|
switch_to(webserver, f"{server}-remove-alias")
|
||||||
check_issuer(webserver, "example.test", "pebble")
|
webserver.wait_for_unit(f"acme-finished-{test_domain}.target")
|
||||||
check_connection(client, "dns.example.test")
|
wait_for_server()
|
||||||
|
check_connection(client, test_domain)
|
||||||
|
rc, _ = client.execute(
|
||||||
|
f"openssl s_client -CAfile /tmp/ca.crt -connect {test_alias}:443"
|
||||||
|
" </dev/null 2>/dev/null | openssl x509 -noout -text"
|
||||||
|
f" | grep DNS: | grep {test_alias}"
|
||||||
|
)
|
||||||
|
assert rc > 0, "Removed extraDomainName was not removed from the cert"
|
||||||
|
|
||||||
|
with subtest("security.acme changes reflect on web server"):
|
||||||
|
# Switch back to normal server config first, reset everything.
|
||||||
|
switch_to(webserver, server)
|
||||||
|
wait_for_server()
|
||||||
|
switch_to(webserver, f"{server}-change-acme-conf")
|
||||||
|
webserver.wait_for_unit(f"acme-finished-{test_domain}.target")
|
||||||
|
wait_for_server()
|
||||||
|
check_connection_key_bits(client, test_domain, "384")
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
|
|
@ -105,6 +105,7 @@ in
|
||||||
dnscrypt-wrapper = handleTestOn ["x86_64-linux"] ./dnscrypt-wrapper {};
|
dnscrypt-wrapper = handleTestOn ["x86_64-linux"] ./dnscrypt-wrapper {};
|
||||||
doas = handleTest ./doas.nix {};
|
doas = handleTest ./doas.nix {};
|
||||||
docker = handleTestOn ["x86_64-linux"] ./docker.nix {};
|
docker = handleTestOn ["x86_64-linux"] ./docker.nix {};
|
||||||
|
docker-rootless = handleTestOn ["x86_64-linux"] ./docker-rootless.nix {};
|
||||||
docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};
|
docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};
|
||||||
docker-registry = handleTest ./docker-registry.nix {};
|
docker-registry = handleTest ./docker-registry.nix {};
|
||||||
docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
|
docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
|
||||||
|
@ -397,6 +398,7 @@ in
|
||||||
proxy = handleTest ./proxy.nix {};
|
proxy = handleTest ./proxy.nix {};
|
||||||
prowlarr = handleTest ./prowlarr.nix {};
|
prowlarr = handleTest ./prowlarr.nix {};
|
||||||
pt2-clone = handleTest ./pt2-clone.nix {};
|
pt2-clone = handleTest ./pt2-clone.nix {};
|
||||||
|
pulseaudio = discoverTests (import ./pulseaudio.nix);
|
||||||
qboot = handleTestOn ["x86_64-linux" "i686-linux"] ./qboot.nix {};
|
qboot = handleTestOn ["x86_64-linux" "i686-linux"] ./qboot.nix {};
|
||||||
quorum = handleTest ./quorum.nix {};
|
quorum = handleTest ./quorum.nix {};
|
||||||
rabbitmq = handleTest ./rabbitmq.nix {};
|
rabbitmq = handleTest ./rabbitmq.nix {};
|
||||||
|
@ -435,6 +437,7 @@ in
|
||||||
solanum = handleTest ./solanum.nix {};
|
solanum = handleTest ./solanum.nix {};
|
||||||
solr = handleTest ./solr.nix {};
|
solr = handleTest ./solr.nix {};
|
||||||
sonarr = handleTest ./sonarr.nix {};
|
sonarr = handleTest ./sonarr.nix {};
|
||||||
|
sourcehut = handleTest ./sourcehut.nix {};
|
||||||
spacecookie = handleTest ./spacecookie.nix {};
|
spacecookie = handleTest ./spacecookie.nix {};
|
||||||
spark = handleTestOn ["x86_64-linux"] ./spark {};
|
spark = handleTestOn ["x86_64-linux"] ./spark {};
|
||||||
sslh = handleTest ./sslh.nix {};
|
sslh = handleTest ./sslh.nix {};
|
||||||
|
|
|
@ -5,9 +5,11 @@ let
|
||||||
|
|
||||||
in {
|
in {
|
||||||
security.acme = {
|
security.acme = {
|
||||||
|
acceptTerms = true;
|
||||||
|
defaults = {
|
||||||
server = "https://${caDomain}/dir";
|
server = "https://${caDomain}/dir";
|
||||||
email = "hostmaster@example.test";
|
email = "hostmaster@example.test";
|
||||||
acceptTerms = true;
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
security.pki.certificateFiles = [ caCert ];
|
security.pki.certificateFiles = [ caCert ];
|
||||||
|
|
|
@ -120,6 +120,11 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
description = "Pebble ACME server";
|
description = "Pebble ACME server";
|
||||||
wantedBy = [ "network.target" ];
|
wantedBy = [ "network.target" ];
|
||||||
|
environment = {
|
||||||
|
# We're not testing lego, we're just testing our configuration.
|
||||||
|
# No need to sleep.
|
||||||
|
PEBBLE_VA_NOSLEEP = "1";
|
||||||
|
};
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
RuntimeDirectory = "pebble";
|
RuntimeDirectory = "pebble";
|
||||||
|
|
41
third_party/nixpkgs/nixos/tests/docker-rootless.nix
vendored
Normal file
41
third_party/nixpkgs/nixos/tests/docker-rootless.nix
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# This test runs docker and checks if simple container starts
|
||||||
|
|
||||||
|
import ./make-test-python.nix ({ lib, pkgs, ...} : {
|
||||||
|
name = "docker-rootless";
|
||||||
|
meta = with pkgs.lib.maintainers; {
|
||||||
|
maintainers = [ abbradar ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
machine = { pkgs, ... }: {
|
||||||
|
virtualisation.docker.rootless.enable = true;
|
||||||
|
|
||||||
|
users.users.alice = {
|
||||||
|
uid = 1000;
|
||||||
|
isNormalUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = { nodes, ... }:
|
||||||
|
let
|
||||||
|
user = nodes.machine.config.users.users.alice;
|
||||||
|
sudo = lib.concatStringsSep " " [
|
||||||
|
"XDG_RUNTIME_DIR=/run/user/${toString user.uid}"
|
||||||
|
"DOCKER_HOST=unix:///run/user/${toString user.uid}/docker.sock"
|
||||||
|
"sudo" "--preserve-env=XDG_RUNTIME_DIR,DOCKER_HOST" "-u" "alice"
|
||||||
|
];
|
||||||
|
in ''
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
machine.succeed("loginctl enable-linger alice")
|
||||||
|
machine.wait_until_succeeds("${sudo} systemctl --user is-active docker.service")
|
||||||
|
|
||||||
|
machine.succeed("tar cv --files-from /dev/null | ${sudo} docker import - scratchimg")
|
||||||
|
machine.succeed(
|
||||||
|
"${sudo} docker run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
|
||||||
|
)
|
||||||
|
machine.succeed("${sudo} docker ps | grep sleeping")
|
||||||
|
machine.succeed("${sudo} docker stop sleeping")
|
||||||
|
'';
|
||||||
|
})
|
|
@ -17,7 +17,7 @@ let
|
||||||
makeHydraTest = with pkgs.lib; name: package: makeTest {
|
makeHydraTest = with pkgs.lib; name: package: makeTest {
|
||||||
name = "hydra-${name}";
|
name = "hydra-${name}";
|
||||||
meta = with pkgs.lib.maintainers; {
|
meta = with pkgs.lib.maintainers; {
|
||||||
maintainers = [ pstn lewo ma27 ];
|
maintainers = [ lewo ma27 ];
|
||||||
};
|
};
|
||||||
|
|
||||||
machine = { pkgs, lib, ... }: {
|
machine = { pkgs, lib, ... }: {
|
||||||
|
|
|
@ -51,7 +51,6 @@ let
|
||||||
environment.systemPackages = [ kubectl ];
|
environment.systemPackages = [ kubectl ];
|
||||||
services.flannel.iface = "eth1";
|
services.flannel.iface = "eth1";
|
||||||
services.kubernetes = {
|
services.kubernetes = {
|
||||||
addons.dashboard.enable = true;
|
|
||||||
proxy.hostname = "${masterName}.${domain}";
|
proxy.hostname = "${masterName}.${domain}";
|
||||||
|
|
||||||
easyCerts = true;
|
easyCerts = true;
|
||||||
|
|
71
third_party/nixpkgs/nixos/tests/pulseaudio.nix
vendored
Normal file
71
third_party/nixpkgs/nixos/tests/pulseaudio.nix
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
let
|
||||||
|
mkTest = { systemWide ? false }:
|
||||||
|
import ./make-test-python.nix ({ pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
testFile = pkgs.fetchurl {
|
||||||
|
url =
|
||||||
|
"https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3";
|
||||||
|
hash = "sha256-+iggJW8s0/LfA/okfXsB550/55Q0Sq3OoIzuBrzOPJQ=";
|
||||||
|
};
|
||||||
|
|
||||||
|
makeTestPlay = key:
|
||||||
|
{ sox, alsa-utils }:
|
||||||
|
pkgs.writeScriptBin key ''
|
||||||
|
set -euxo pipefail
|
||||||
|
${sox}/bin/play ${testFile}
|
||||||
|
${sox}/bin/sox ${testFile} -t wav - | ${alsa-utils}/bin/aplay
|
||||||
|
touch /tmp/${key}_success
|
||||||
|
'';
|
||||||
|
|
||||||
|
testers = builtins.mapAttrs makeTestPlay {
|
||||||
|
testPlay = { inherit (pkgs) sox alsa-utils; };
|
||||||
|
testPlay32 = { inherit (pkgs.pkgsi686Linux) sox alsa-utils; };
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
name = "pulseaudio${lib.optionalString systemWide "-systemWide"}";
|
||||||
|
meta = with pkgs.lib.maintainers; {
|
||||||
|
maintainers = [ synthetica ] ++ pkgs.pulseaudio.meta.maintainers;
|
||||||
|
};
|
||||||
|
|
||||||
|
machine = { ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ ./common/wayland-cage.nix ];
|
||||||
|
hardware.pulseaudio = {
|
||||||
|
enable = true;
|
||||||
|
support32Bit = true;
|
||||||
|
inherit systemWide;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [ testers.testPlay pkgs.pavucontrol ]
|
||||||
|
++ lib.optional pkgs.stdenv.isx86_64 testers.testPlay32;
|
||||||
|
} // lib.optionalAttrs systemWide {
|
||||||
|
users.users.alice.extraGroups = [ "audio" ];
|
||||||
|
systemd.services.pulseaudio.wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
enableOCR = true;
|
||||||
|
|
||||||
|
testScript = { ... }: ''
|
||||||
|
machine.wait_until_succeeds("pgrep xterm")
|
||||||
|
machine.wait_for_text("alice@machine")
|
||||||
|
|
||||||
|
machine.send_chars("testPlay \n")
|
||||||
|
machine.wait_for_file("/tmp/testPlay_success")
|
||||||
|
${lib.optionalString pkgs.stdenv.isx86_64 ''
|
||||||
|
machine.send_chars("testPlay32 \n")
|
||||||
|
machine.wait_for_file("/tmp/testPlay32_success")
|
||||||
|
''}
|
||||||
|
machine.screenshot("testPlay")
|
||||||
|
|
||||||
|
# Pavucontrol only loads when Pulseaudio is running. If it isn't, the
|
||||||
|
# text "Playback" (one of the tabs) will never show.
|
||||||
|
machine.send_chars("pavucontrol\n")
|
||||||
|
machine.wait_for_text("Playback")
|
||||||
|
machine.screenshot("Pavucontrol")
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
in builtins.mapAttrs (key: val: mkTest val) {
|
||||||
|
user = { systemWide = false; };
|
||||||
|
system = { systemWide = true; };
|
||||||
|
}
|
188
third_party/nixpkgs/nixos/tests/sourcehut.nix
vendored
188
third_party/nixpkgs/nixos/tests/sourcehut.nix
vendored
|
@ -1,29 +1,197 @@
|
||||||
import ./make-test-python.nix ({ pkgs, ... }:
|
import ./make-test-python.nix ({ pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
domain = "sourcehut.localdomain";
|
||||||
|
|
||||||
|
# Note that wildcard certificates just under the TLD (eg. *.com)
|
||||||
|
# would be rejected by clients like curl.
|
||||||
|
tls-cert = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } ''
|
||||||
|
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 36500 \
|
||||||
|
-subj '/CN=${domain}' -extensions v3_req \
|
||||||
|
-addext 'subjectAltName = DNS:*.${domain}'
|
||||||
|
install -D -t $out key.pem cert.pem
|
||||||
|
'';
|
||||||
|
|
||||||
|
images = {
|
||||||
|
nixos.unstable.x86_64 =
|
||||||
|
let
|
||||||
|
systemConfig = { pkgs, ... }: {
|
||||||
|
# passwordless ssh server
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
permitRootLogin = "yes";
|
||||||
|
extraConfig = "PermitEmptyPasswords yes";
|
||||||
|
};
|
||||||
|
|
||||||
|
users = {
|
||||||
|
mutableUsers = false;
|
||||||
|
# build user
|
||||||
|
extraUsers."build" = {
|
||||||
|
isNormalUser = true;
|
||||||
|
uid = 1000;
|
||||||
|
extraGroups = [ "wheel" ];
|
||||||
|
password = "";
|
||||||
|
};
|
||||||
|
users.root.password = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
nix.trustedUsers = [ "root" "build" ];
|
||||||
|
documentation.nixos.enable = false;
|
||||||
|
|
||||||
|
# builds.sr.ht-image-specific network settings
|
||||||
|
networking = {
|
||||||
|
hostName = "build";
|
||||||
|
dhcpcd.enable = false;
|
||||||
|
defaultGateway.address = "10.0.2.2";
|
||||||
|
usePredictableInterfaceNames = false;
|
||||||
|
interfaces."eth0".ipv4.addresses = [{
|
||||||
|
address = "10.0.2.15";
|
||||||
|
prefixLength = 25;
|
||||||
|
}];
|
||||||
|
enableIPv6 = false;
|
||||||
|
nameservers = [
|
||||||
|
# OpenNIC anycast
|
||||||
|
"185.121.177.177"
|
||||||
|
"169.239.202.202"
|
||||||
|
# Google
|
||||||
|
"8.8.8.8"
|
||||||
|
];
|
||||||
|
firewall.allowedTCPPorts = [ 22 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
pkgs.gitMinimal
|
||||||
|
#pkgs.mercurial
|
||||||
|
pkgs.curl
|
||||||
|
pkgs.gnupg
|
||||||
|
];
|
||||||
|
};
|
||||||
|
qemuConfig = { pkgs, ... }: {
|
||||||
|
imports = [ systemConfig ];
|
||||||
|
fileSystems."/".device = "/dev/disk/by-label/nixos";
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"ahci"
|
||||||
|
"ehci_pci"
|
||||||
|
"sd_mod"
|
||||||
|
"usb_storage"
|
||||||
|
"usbhid"
|
||||||
|
"virtio_balloon"
|
||||||
|
"virtio_blk"
|
||||||
|
"virtio_pci"
|
||||||
|
"virtio_ring"
|
||||||
|
"xhci_pci"
|
||||||
|
];
|
||||||
|
boot.loader = {
|
||||||
|
grub = {
|
||||||
|
version = 2;
|
||||||
|
device = "/dev/vda";
|
||||||
|
};
|
||||||
|
timeout = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = (import (pkgs.path + "/nixos/lib/eval-config.nix") {
|
||||||
|
inherit pkgs; modules = [ qemuConfig ];
|
||||||
|
system = "x86_64-linux";
|
||||||
|
}).config;
|
||||||
|
in
|
||||||
|
import (pkgs.path + "/nixos/lib/make-disk-image.nix") {
|
||||||
|
inherit pkgs lib config;
|
||||||
|
diskSize = 16000;
|
||||||
|
format = "qcow2-compressed";
|
||||||
|
contents = [
|
||||||
|
{ source = pkgs.writeText "gitconfig" ''
|
||||||
|
[user]
|
||||||
|
name = builds.sr.ht
|
||||||
|
email = build@sr.ht
|
||||||
|
'';
|
||||||
|
target = "/home/build/.gitconfig";
|
||||||
|
user = "build";
|
||||||
|
group = "users";
|
||||||
|
mode = "644";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
{
|
{
|
||||||
name = "sourcehut";
|
name = "sourcehut";
|
||||||
|
|
||||||
meta.maintainers = [ pkgs.lib.maintainers.tomberek ];
|
meta.maintainers = [ pkgs.lib.maintainers.tomberek ];
|
||||||
|
|
||||||
machine = { config, pkgs, ... }: {
|
machine = { config, pkgs, nodes, ... }: {
|
||||||
virtualisation.memorySize = 2048;
|
# buildsrht needs space
|
||||||
networking.firewall.allowedTCPPorts = [ 80 ];
|
virtualisation.diskSize = 4 * 1024;
|
||||||
|
virtualisation.memorySize = 2 * 1024;
|
||||||
|
networking.domain = domain;
|
||||||
|
networking.extraHosts = ''
|
||||||
|
${config.networking.primaryIPAddress} meta.${domain}
|
||||||
|
${config.networking.primaryIPAddress} builds.${domain}
|
||||||
|
'';
|
||||||
|
|
||||||
services.sourcehut = {
|
services.sourcehut = {
|
||||||
enable = true;
|
enable = true;
|
||||||
services = [ "meta" ];
|
services = [ "meta" "builds" ];
|
||||||
originBase = "sourcehut";
|
nginx.enable = true;
|
||||||
settings."sr.ht".service-key = "8888888888888888888888888888888888888888888888888888888888888888";
|
nginx.virtualHost = {
|
||||||
settings."sr.ht".network-key = "0000000000000000000000000000000000000000000=";
|
forceSSL = true;
|
||||||
settings.webhooks.private-key = "0000000000000000000000000000000000000000000=";
|
sslCertificate = "${tls-cert}/cert.pem";
|
||||||
|
sslCertificateKey = "${tls-cert}/key.pem";
|
||||||
|
};
|
||||||
|
postgresql.enable = true;
|
||||||
|
redis.enable = true;
|
||||||
|
|
||||||
|
meta.enable = true;
|
||||||
|
builds = {
|
||||||
|
enable = true;
|
||||||
|
# FIXME: see why it does not seem to activate fully.
|
||||||
|
#enableWorker = true;
|
||||||
|
inherit images;
|
||||||
|
};
|
||||||
|
settings."sr.ht" = {
|
||||||
|
global-domain = config.networking.domain;
|
||||||
|
service-key = pkgs.writeText "service-key" "8b327279b77e32a3620e2fc9aabce491cc46e7d821fd6713b2a2e650ce114d01";
|
||||||
|
network-key = pkgs.writeText "network-key" "cEEmc30BRBGkgQZcHFksiG7hjc6_dK1XR2Oo5Jb9_nQ=";
|
||||||
|
};
|
||||||
|
settings."builds.sr.ht" = {
|
||||||
|
oauth-client-secret = pkgs.writeText "buildsrht-oauth-client-secret" "2260e9c4d9b8dcedcef642860e0504bc";
|
||||||
|
oauth-client-id = "299db9f9c2013170";
|
||||||
|
};
|
||||||
|
settings.webhooks.private-key = pkgs.writeText "webhook-key" "Ra3IjxgFiwG9jxgp4WALQIZw/BMYt30xWiOsqD0J7EA=";
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 443 ];
|
||||||
|
security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ];
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
recommendedGzipSettings = true;
|
||||||
|
recommendedOptimisation = true;
|
||||||
|
recommendedTlsSettings = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
enableTCPIP = false;
|
||||||
|
settings.unix_socket_permissions = "0770";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
start_all()
|
start_all()
|
||||||
machine.wait_for_unit("multi-user.target")
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
# Testing metasrht
|
||||||
|
machine.wait_for_unit("metasrht-api.service")
|
||||||
machine.wait_for_unit("metasrht.service")
|
machine.wait_for_unit("metasrht.service")
|
||||||
machine.wait_for_open_port(5000)
|
machine.wait_for_open_port(5000)
|
||||||
machine.succeed("curl -sL http://localhost:5000 | grep meta.sourcehut")
|
machine.succeed("curl -sL http://localhost:5000 | grep meta.${domain}")
|
||||||
|
machine.succeed("curl -sL http://meta.${domain} | grep meta.${domain}")
|
||||||
|
|
||||||
|
# Testing buildsrht
|
||||||
|
machine.wait_for_unit("buildsrht.service")
|
||||||
|
machine.wait_for_open_port(5002)
|
||||||
|
machine.succeed("curl -sL http://localhost:5002 | grep builds.${domain}")
|
||||||
|
#machine.wait_for_unit("buildsrht-worker.service")
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,68 +1,76 @@
|
||||||
{ alsa-lib
|
{ alsa-lib, at-spi2-core, cmake, curl, dbus, libepoxy, fetchFromGitHub, freeglut
|
||||||
, curl
|
, freetype, gcc-unwrapped, gtk3, lib, libGL, libXcursor, libXdmcp, libXext
|
||||||
, fetchFromGitHub
|
, libXinerama, libXrandr, libXtst, libdatrie, libjack2, libpsl, libselinux
|
||||||
, freeglut
|
, libsepol, libsysprof-capture, libthai, libxkbcommon, lv2, pcre, pkg-config
|
||||||
, freetype
|
, python3, sqlite, stdenv }:
|
||||||
, libGL
|
|
||||||
, libXcursor
|
|
||||||
, libXext
|
|
||||||
, libXinerama
|
|
||||||
, libXrandr
|
|
||||||
, libjack2
|
|
||||||
, pkg-config
|
|
||||||
, python3
|
|
||||||
, stdenv
|
|
||||||
, lib
|
|
||||||
}:
|
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "CHOWTapeModel";
|
pname = "CHOWTapeModel";
|
||||||
version = "unstable-2020-12-12";
|
version = "2.10.0";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "jatinchowdhury18";
|
owner = "jatinchowdhury18";
|
||||||
repo = "AnalogTapeModel";
|
repo = "AnalogTapeModel";
|
||||||
rev = "a7cf10c3f790d306ce5743bb731e4bc2c1230d70";
|
rev = "v${version}";
|
||||||
sha256 = "09nq8x2dwabncbp039dqm1brzcz55zg9kpxd4p5348xlaz5m4661";
|
sha256 = "sha256-iuT7OBRBtMkjcTHayCcne1mNqkcxzKnEYl62n65V7Z4=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [ pkg-config cmake ];
|
||||||
pkg-config
|
|
||||||
];
|
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
alsa-lib
|
alsa-lib
|
||||||
|
at-spi2-core
|
||||||
curl
|
curl
|
||||||
|
dbus
|
||||||
|
libepoxy
|
||||||
freeglut
|
freeglut
|
||||||
freetype
|
freetype
|
||||||
|
gtk3
|
||||||
libGL
|
libGL
|
||||||
libXcursor
|
libXcursor
|
||||||
|
libXdmcp
|
||||||
libXext
|
libXext
|
||||||
libXinerama
|
libXinerama
|
||||||
libXrandr
|
libXrandr
|
||||||
|
libXtst
|
||||||
|
libdatrie
|
||||||
libjack2
|
libjack2
|
||||||
|
libpsl
|
||||||
|
libselinux
|
||||||
|
libsepol
|
||||||
|
libsysprof-capture
|
||||||
|
libthai
|
||||||
|
libxkbcommon
|
||||||
|
lv2
|
||||||
|
pcre
|
||||||
python3
|
python3
|
||||||
|
sqlite
|
||||||
|
gcc-unwrapped
|
||||||
];
|
];
|
||||||
|
|
||||||
buildPhase = ''
|
cmakeFlags = [
|
||||||
cd Plugin/
|
"-DCMAKE_AR=${gcc-unwrapped}/bin/gcc-ar"
|
||||||
./build_linux.sh
|
"-DCMAKE_RANLIB=${gcc-unwrapped}/bin/gcc-ranlib"
|
||||||
'';
|
"-DCMAKE_NM=${gcc-unwrapped}/bin/gcc-nm"
|
||||||
|
];
|
||||||
|
|
||||||
|
postPatch = "cd Plugin";
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out/lib/lv2 $out/lib/vst3 $out/bin $out/share/doc/CHOWTapeModel/
|
mkdir -p $out/lib/lv2 $out/lib/vst3 $out/bin $out/share/doc/CHOWTapeModel/
|
||||||
cd Builds/LinuxMakefile/build/
|
cd CHOWTapeModel_artefacts/Release
|
||||||
cp CHOWTapeModel.a $out/lib
|
cp libCHOWTapeModel_SharedCode.a $out/lib
|
||||||
cp -r CHOWTapeModel.lv2 $out/lib/lv2
|
cp -r LV2/CHOWTapeModel.lv2 $out/lib/lv2
|
||||||
cp -r CHOWTapeModel.vst3 $out/lib/vst3
|
cp -r VST3/CHOWTapeModel.vst3 $out/lib/vst3
|
||||||
cp CHOWTapeModel $out/bin
|
cp Standalone/CHOWTapeModel $out/bin
|
||||||
cp ../../../../Manual/ChowTapeManual.pdf $out/share/doc/CHOWTapeModel/
|
cp ../../../../Manual/ChowTapeManual.pdf $out/share/doc/CHOWTapeModel/
|
||||||
'';
|
'';
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://github.com/jatinchowdhury18/AnalogTapeModel";
|
homepage = "https://github.com/jatinchowdhury18/AnalogTapeModel";
|
||||||
description = "Physical modelling signal processing for analog tape recording. LV2, VST3 and standalone";
|
description =
|
||||||
|
"Physical modelling signal processing for analog tape recording. LV2, VST3 and standalone";
|
||||||
license = with licenses; [ gpl3Only ];
|
license = with licenses; [ gpl3Only ];
|
||||||
maintainers = with maintainers; [ magnetophon ];
|
maintainers = with maintainers; [ magnetophon ];
|
||||||
platforms = platforms.linux;
|
platforms = platforms.linux;
|
||||||
|
|
|
@ -28,11 +28,11 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "kid3";
|
pname = "kid3";
|
||||||
version = "3.8.7";
|
version = "3.9.0";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://download.kde.org/stable/${pname}/${version}/${pname}-${version}.tar.xz";
|
url = "https://download.kde.org/stable/${pname}/${version}/${pname}-${version}.tar.xz";
|
||||||
sha256 = "sha256-Dr+NLh5ajG42jRKt1Swq6mccPfuAXRvhhoTNuO8lnI0=";
|
sha256 = "sha256-d0Y+swzzGk1FzQ3EK8sN8i1Nf6CRIPMAYgTUYN71FXU=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
|
|
@ -9,6 +9,8 @@ lib.makeScope newScope (self: with self; {
|
||||||
|
|
||||||
mopidy-iris = callPackage ./iris.nix { };
|
mopidy-iris = callPackage ./iris.nix { };
|
||||||
|
|
||||||
|
mopidy-jellyfin = callPackage ./jellyfin.nix { };
|
||||||
|
|
||||||
mopidy-local = callPackage ./local.nix { };
|
mopidy-local = callPackage ./local.nix { };
|
||||||
|
|
||||||
mopidy-moped = callPackage ./moped.nix { };
|
mopidy-moped = callPackage ./moped.nix { };
|
||||||
|
|
25
third_party/nixpkgs/pkgs/applications/audio/mopidy/jellyfin.nix
vendored
Normal file
25
third_party/nixpkgs/pkgs/applications/audio/mopidy/jellyfin.nix
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{ lib, python3Packages, mopidy }:
|
||||||
|
|
||||||
|
python3Packages.buildPythonApplication rec {
|
||||||
|
pname = "mopidy-jellyfin";
|
||||||
|
version = "1.0.2";
|
||||||
|
|
||||||
|
src = python3Packages.fetchPypi {
|
||||||
|
inherit version;
|
||||||
|
pname = "Mopidy-Jellyfin";
|
||||||
|
sha256 = "0j7v5xx3c401r5dw1sqm1n2263chjga1d3ml85rg79hjhhhacy75";
|
||||||
|
};
|
||||||
|
|
||||||
|
propagatedBuildInputs = [ mopidy python3Packages.unidecode python3Packages.websocket-client ];
|
||||||
|
|
||||||
|
# no tests implemented
|
||||||
|
doCheck = false;
|
||||||
|
pythonImportsCheck = [ "mopidy_jellyfin" ];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
homepage = "https://github.com/jellyfin/mopidy-jellyfin";
|
||||||
|
description = "Mopidy extension for playing audio files from Jellyfin";
|
||||||
|
license = licenses.asl20;
|
||||||
|
maintainers = [ maintainers.pstn ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -11,20 +11,22 @@
|
||||||
, libmicrohttpd
|
, libmicrohttpd
|
||||||
, ncurses
|
, ncurses
|
||||||
, pulseaudio
|
, pulseaudio
|
||||||
, lib, stdenv
|
, lib
|
||||||
|
, stdenv
|
||||||
, taglib
|
, taglib
|
||||||
, systemdSupport ? stdenv.isLinux, systemd
|
, systemdSupport ? stdenv.isLinux
|
||||||
|
, systemd
|
||||||
}:
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "musikcube";
|
pname = "musikcube";
|
||||||
version = "0.96.7";
|
version = "0.96.10";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "clangen";
|
owner = "clangen";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "1y00vwn1h10cfflxrm5bk271ak9gilhjycgi44hlkkhmf5bdgn35";
|
sha256 = "sha256-Aa52pRGq99Pt++aEVZdmVNhhQuBajgfZp39L1AfKvho=";
|
||||||
};
|
};
|
||||||
|
|
||||||
patches = [
|
patches = [
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
, lib
|
, lib
|
||||||
, stdenv
|
, stdenv
|
||||||
, fetchFromGitHub
|
, fetchFromGitHub
|
||||||
, fetchpatch
|
|
||||||
, nix-update-script
|
, nix-update-script
|
||||||
, qmake
|
, qmake
|
||||||
, pkg-config
|
, pkg-config
|
||||||
|
@ -14,25 +13,15 @@
|
||||||
|
|
||||||
mkDerivation rec {
|
mkDerivation rec {
|
||||||
pname = "ptcollab";
|
pname = "ptcollab";
|
||||||
version = "0.5.0.1";
|
version = "0.5.0.3";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "yuxshao";
|
owner = "yuxshao";
|
||||||
repo = "ptcollab";
|
repo = "ptcollab";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "10v310smm0df233wlh1kqv8i36lsg1m36v0flrhs2202k50d69ri";
|
sha256 = "sha256-8bgi621psvUlhiLyZ15tKGmGOs6HTf5/6Ru2Z9l8QIo=";
|
||||||
};
|
};
|
||||||
|
|
||||||
patches = [
|
|
||||||
# Lifts macOS version restriction
|
|
||||||
# Remove when version > 0.5.0.1
|
|
||||||
(fetchpatch {
|
|
||||||
name = "0001-ptcollab-lift-10.14-deployment-target-limitation.patch";
|
|
||||||
url = "https://github.com/yuxshao/ptcollab/commit/a9664b5953e1046e1f7da3b38744f33a7ff0ea24.patch";
|
|
||||||
sha256 = "0qgpv5hmb4504kamdgxalrhc4zb9rdxln23s7qwc7ikafg54h1fm";
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
nativeBuildInputs = [ qmake pkg-config ];
|
nativeBuildInputs = [ qmake pkg-config ];
|
||||||
|
|
||||||
buildInputs = [ qtbase qtmultimedia libvorbis rtmidi ];
|
buildInputs = [ qtbase qtmultimedia libvorbis rtmidi ];
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
|
|
||||||
mkDerivation rec {
|
mkDerivation rec {
|
||||||
pname = "qpwgraph";
|
pname = "qpwgraph";
|
||||||
version = "0.1.0";
|
version = "0.1.1";
|
||||||
|
|
||||||
src = fetchFromGitLab {
|
src = fetchFromGitLab {
|
||||||
domain = "gitlab.freedesktop.org";
|
domain = "gitlab.freedesktop.org";
|
||||||
owner = "rncbc";
|
owner = "rncbc";
|
||||||
repo = "qpwgraph";
|
repo = "qpwgraph";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-VDLfOcIXM3+04tEvPzKDEKMperMhB5hDo1MlttS04yM=";
|
sha256 = "sha256-r3FoAV0wah9fwnqyMyu8927c4Uj0zZoQNvLoXP5AP/E=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ cmake pkg-config ];
|
nativeBuildInputs = [ cmake pkg-config ];
|
||||||
|
|
|
@ -17,13 +17,13 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "reaper";
|
pname = "reaper";
|
||||||
version = "6.38";
|
version = "6.43";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://www.reaper.fm/files/${lib.versions.major version}.x/reaper${builtins.replaceStrings ["."] [""] version}_linux_${stdenv.hostPlatform.qemuArch}.tar.xz";
|
url = "https://www.reaper.fm/files/${lib.versions.major version}.x/reaper${builtins.replaceStrings ["."] [""] version}_linux_${stdenv.hostPlatform.qemuArch}.tar.xz";
|
||||||
hash = {
|
hash = {
|
||||||
x86_64-linux = "sha256-K5EnrmzP8pyW9dR1fbMzkPzpS6aHm8JF1+m3afnH4rU=";
|
x86_64-linux = "sha256-VQ91px9YZWbrw31fFQxS+H/6fsjkLDrYU6FtI8eSq6E=";
|
||||||
aarch64-linux = "sha256-6wNWDXjQNyfU2l9Xi9JtmAuoKtHuIY5cvNMjYkwh2Sk=";
|
aarch64-linux = "sha256-x6z5+H7ASWiuNL0maNGK05VmJptHdFGRiFf6DgwlZDw=";
|
||||||
}.${stdenv.hostPlatform.system};
|
}.${stdenv.hostPlatform.system};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,6 +78,6 @@ stdenv.mkDerivation rec {
|
||||||
homepage = "https://www.reaper.fm/";
|
homepage = "https://www.reaper.fm/";
|
||||||
license = licenses.unfree;
|
license = licenses.unfree;
|
||||||
platforms = [ "x86_64-linux" "aarch64-linux" ];
|
platforms = [ "x86_64-linux" "aarch64-linux" ];
|
||||||
maintainers = with maintainers; [ jfrankenau ilian orivej ];
|
maintainers = with maintainers; [ jfrankenau ilian orivej uniquepointer ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
{ lib, stdenv, fetchFromGitHub
|
{ lib, stdenv, fetchFromGitHub, libjack2, libsndfile, xorg, freetype
|
||||||
, libjack2, libsndfile, xorg, freetype, libxkbcommon
|
, libxkbcommon, cairo, glib, gnome, flac, libogg, libvorbis, libopus, cmake
|
||||||
, cairo, glib, gnome, flac, libogg, libvorbis, libopus
|
, pango, pkg-config }:
|
||||||
, cmake, pkg-config
|
|
||||||
}:
|
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "sfizz";
|
pname = "sfizz";
|
||||||
version = "0.5.1";
|
version = "1.1.1";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "sfztools";
|
owner = "sfztools";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "sha256-3RdY5+BPsdk6vctDy24w5aJsVOV9qzSgXs62Pm5UEKs=";
|
sha256 = "1gzpbns89j6ggzfjjvyhgigynsv20synrs7lmc32hwp4g73l0j7n";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,18 +35,18 @@ stdenv.mkDerivation rec {
|
||||||
glib
|
glib
|
||||||
gnome.zenity
|
gnome.zenity
|
||||||
freetype
|
freetype
|
||||||
|
pango
|
||||||
];
|
];
|
||||||
nativeBuildInputs = [ cmake pkg-config ];
|
nativeBuildInputs = [ cmake pkg-config ];
|
||||||
|
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
substituteInPlace editor/external/vstgui4/vstgui/lib/platform/linux/x11fileselector.cpp \
|
substituteInPlace plugins/editor/external/vstgui4/vstgui/lib/platform/linux/x11fileselector.cpp \
|
||||||
--replace '"/usr/bin/zenity' '"${gnome.zenity}/bin/zenity'
|
--replace 'zenitypath = "zenity"' 'zenitypath = "${gnome.zenity}/bin/zenity"'
|
||||||
|
substituteInPlace plugins/editor/src/editor/NativeHelpers.cpp \
|
||||||
|
--replace '/usr/bin/zenity' '${gnome.zenity}/bin/zenity'
|
||||||
'';
|
'';
|
||||||
|
|
||||||
cmakeFlags = [
|
cmakeFlags = [ "-DCMAKE_BUILD_TYPE=Release" "-DSFIZZ_TESTS=ON" ];
|
||||||
"-DCMAKE_BUILD_TYPE=Release"
|
|
||||||
"-DSFIZZ_TESTS=ON"
|
|
||||||
];
|
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://github.com/sfztools/sfizz";
|
homepage = "https://github.com/sfztools/sfizz";
|
||||||
|
|
|
@ -33,7 +33,7 @@ stdenv.mkDerivation rec {
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
description = "A powerful editor targeted towards programmers and webdevelopers";
|
description = "A powerful editor targeted towards programmers and webdevelopers";
|
||||||
homepage = "http://bluefish.openoffice.nl/";
|
homepage = "https://bluefish.openoffice.nl/";
|
||||||
license = licenses.gpl3Plus;
|
license = licenses.gpl3Plus;
|
||||||
maintainers = with maintainers; [ vbgl ];
|
maintainers = with maintainers; [ vbgl ];
|
||||||
platforms = platforms.all;
|
platforms = platforms.all;
|
||||||
|
|
|
@ -15,7 +15,7 @@ stdenv.mkDerivation {
|
||||||
'';
|
'';
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
homepage = "http://bruda.ca/emacs/prolog_mode_for_emacs/";
|
homepage = "https://bruda.ca/emacs/prolog_mode_for_emacs/";
|
||||||
description = "Prolog mode for Emacs";
|
description = "Prolog mode for Emacs";
|
||||||
license = lib.licenses.gpl2Plus;
|
license = lib.licenses.gpl2Plus;
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
, siteStart ? ./site-start.el
|
, siteStart ? ./site-start.el
|
||||||
, nativeComp ? false
|
, nativeComp ? false
|
||||||
, withPgtk ? false
|
, withPgtk ? false
|
||||||
|
, withXinput2 ? false
|
||||||
, withImageMagick ? lib.versionOlder version "27" && (withX || withNS)
|
, withImageMagick ? lib.versionOlder version "27" && (withX || withNS)
|
||||||
, toolkit ? (
|
, toolkit ? (
|
||||||
if withGTK2 then "gtk2"
|
if withGTK2 then "gtk2"
|
||||||
|
@ -152,6 +153,7 @@ let emacs = stdenv.mkDerivation (lib.optionalAttrs nativeComp {
|
||||||
++ lib.optional nativeComp "--with-native-compilation"
|
++ lib.optional nativeComp "--with-native-compilation"
|
||||||
++ lib.optional withImageMagick "--with-imagemagick"
|
++ lib.optional withImageMagick "--with-imagemagick"
|
||||||
++ lib.optional withPgtk "--with-pgtk"
|
++ lib.optional withPgtk "--with-pgtk"
|
||||||
|
++ lib.optional withXinput2 "--with-xinput2"
|
||||||
;
|
;
|
||||||
|
|
||||||
installTargets = [ "tags" "install" ];
|
installTargets = [ "tags" "install" ];
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
|
|
||||||
mkDerivation rec {
|
mkDerivation rec {
|
||||||
pname = "ghostwriter";
|
pname = "ghostwriter";
|
||||||
version = "2.1.0";
|
version = "2.1.1";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "wereturtle";
|
owner = "wereturtle";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "sha256-NPuwT0msFvGyS33X7lefdPZZ3AC4pZb1tvmOzzlQlgc=";
|
hash = "sha256-w4qCJgfBnN1PpPfhdsLdBpCRAWai9RrwU3LZl8DdEcw=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ qmake pkg-config qttools ];
|
nativeBuildInputs = [ qmake pkg-config qttools ];
|
||||||
|
|
|
@ -91,6 +91,10 @@ let
|
||||||
patchelf --set-interpreter $interp $out/goland*/plugins/go/lib/dlv/linux/dlv
|
patchelf --set-interpreter $interp $out/goland*/plugins/go/lib/dlv/linux/dlv
|
||||||
|
|
||||||
chmod +x $out/goland*/plugins/go/lib/dlv/linux/dlv
|
chmod +x $out/goland*/plugins/go/lib/dlv/linux/dlv
|
||||||
|
|
||||||
|
# fortify source breaks build since delve compiles with -O0
|
||||||
|
wrapProgram $out/goland*/plugins/go/lib/dlv/linux/dlv \
|
||||||
|
--prefix disableHardening " " fortify
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{ lib, stdenv, fetchFromGitHub, pkg-config, libtool
|
{ lib, stdenv, fetchurl, pkg-config, libtool
|
||||||
, bzip2, zlib, libX11, libXext, libXt, fontconfig, freetype, ghostscript, libjpeg, djvulibre
|
, bzip2, zlib, libX11, libXext, libXt, fontconfig, freetype, ghostscript, libjpeg, djvulibre
|
||||||
, lcms2, openexr, libjxl, libpng, liblqr1, libraw, librsvg, libtiff, libxml2, openjpeg, libwebp, libheif
|
, lcms2, openexr, libjxl, libpng, liblqr1, libraw, librsvg, libtiff, libxml2, openjpeg, libwebp, libheif
|
||||||
, ApplicationServices
|
, ApplicationServices
|
||||||
|
@ -18,13 +18,11 @@ in
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "imagemagick";
|
pname = "imagemagick";
|
||||||
version = "7.1.0-17";
|
version = "7.1.0-19";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchurl {
|
||||||
owner = "ImageMagick";
|
url = "https://download.imagemagick.org/ImageMagick/download/releases/ImageMagick-${version}.tar.xz";
|
||||||
repo = "ImageMagick";
|
hash = "sha256-P9eRdKsPMLwWQ68+ZU8dL/zDqVVCY5gRVWiLT0n3/Xc=";
|
||||||
rev = version;
|
|
||||||
sha256 = "sha256-P6w7dDDvY8r55qN3hnsuzO8kp85gxp2t6vShmhoPOgs=";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = [ "out" "dev" "doc" ]; # bin/ isn't really big
|
outputs = [ "out" "dev" "doc" ]; # bin/ isn't really big
|
||||||
|
|
|
@ -53,13 +53,13 @@ let
|
||||||
python = python2.withPackages (pp: [ pp.pygtk ]);
|
python = python2.withPackages (pp: [ pp.pygtk ]);
|
||||||
in stdenv.mkDerivation rec {
|
in stdenv.mkDerivation rec {
|
||||||
pname = "gimp";
|
pname = "gimp";
|
||||||
version = "2.10.28";
|
version = "2.10.30";
|
||||||
|
|
||||||
outputs = [ "out" "dev" ];
|
outputs = [ "out" "dev" ];
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "http://download.gimp.org/pub/gimp/v${lib.versions.majorMinor version}/${pname}-${version}.tar.bz2";
|
url = "http://download.gimp.org/pub/gimp/v${lib.versions.majorMinor version}/${pname}-${version}.tar.bz2";
|
||||||
sha256 = "T03CLP8atfAm/qoqtV4Fd1s6EeGYGGtHvat5y/oHiCY=";
|
sha256 = "iIFdqnbtfUJ37rNTNYuvoRbNL80shh2VuVE1wdUrZ9w=";
|
||||||
};
|
};
|
||||||
|
|
||||||
patches = [
|
patches = [
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
, copyDesktopItems
|
, copyDesktopItems
|
||||||
, fontconfig
|
, fontconfig
|
||||||
, libpng
|
, libpng
|
||||||
|
, pipewire
|
||||||
|
, makeWrapper
|
||||||
, autoPatchelfHook
|
, autoPatchelfHook
|
||||||
}:
|
}:
|
||||||
|
|
||||||
|
@ -38,6 +40,7 @@ stdenv.mkDerivation rec {
|
||||||
fontconfig
|
fontconfig
|
||||||
libva
|
libva
|
||||||
gst_all_1.gst-plugins-base
|
gst_all_1.gst-plugins-base
|
||||||
|
pipewire
|
||||||
# autoPatchelfHook complains if these are missing, even on wayland
|
# autoPatchelfHook complains if these are missing, even on wayland
|
||||||
xorg.libXft
|
xorg.libXft
|
||||||
xorg.libXinerama
|
xorg.libXinerama
|
||||||
|
@ -47,12 +50,22 @@ stdenv.mkDerivation rec {
|
||||||
xorg.libXtst
|
xorg.libXtst
|
||||||
];
|
];
|
||||||
|
|
||||||
nativeBuildInputs = [ copyDesktopItems autoPatchelfHook ];
|
nativeBuildInputs = [ copyDesktopItems autoPatchelfHook makeWrapper ];
|
||||||
|
|
||||||
|
postFixup = let
|
||||||
|
GST_PLUGIN_PATH = lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" [
|
||||||
|
gst_all_1.gst-plugins-base
|
||||||
|
pipewire
|
||||||
|
];
|
||||||
|
in ''
|
||||||
|
wrapProgram $out/bin/weylus --prefix GST_PLUGIN_PATH : ${GST_PLUGIN_PATH}
|
||||||
|
'';
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
description = "Use your tablet as graphic tablet/touch screen on your computer";
|
description = "Use your tablet as graphic tablet/touch screen on your computer";
|
||||||
homepage = "https://github.com/H-M-H/Weylus";
|
homepage = "https://github.com/H-M-H/Weylus";
|
||||||
license = with licenses; [ agpl3Only ];
|
license = with licenses; [ agpl3Only ];
|
||||||
maintainers = with maintainers; [ lom ];
|
maintainers = with maintainers; [ lom ];
|
||||||
|
platforms = [ "x86_64-linux" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
mkDerivation {
|
mkDerivation {
|
||||||
pname = "kalzium";
|
pname = "kalzium";
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://kde.org/applications/en/utilities/org.kde.kalzium";
|
homepage = "https://edu.kde.org/kalzium/";
|
||||||
description = "Program that shows you the Periodic Table of Elements";
|
description = "Program that shows you the Periodic Table of Elements";
|
||||||
maintainers = with maintainers; [ freezeboy ];
|
maintainers = with maintainers; [ freezeboy ];
|
||||||
license = licenses.gpl2Plus;
|
license = licenses.gpl2Plus;
|
||||||
|
|
|
@ -17,7 +17,7 @@ mkDerivation {
|
||||||
meta = {
|
meta = {
|
||||||
description = "Plugins for KDE-based image applications";
|
description = "Plugins for KDE-based image applications";
|
||||||
license = lib.licenses.gpl2;
|
license = lib.licenses.gpl2;
|
||||||
homepage = "https://cgit.kde.org/kipi-plugins.git";
|
homepage = "https://github.com/KDE/kipi-plugins";
|
||||||
maintainers = with lib.maintainers; [ ttuegel ];
|
maintainers = with lib.maintainers; [ ttuegel ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
mkDerivation {
|
mkDerivation {
|
||||||
pname = "klettres";
|
pname = "klettres";
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://kde.org/applications/en/utilities/org.kde.klettres";
|
homepage = "https://invent.kde.org/education/klettres";
|
||||||
description = "An application specially designed to help the user to learn an alphabet";
|
description = "An application specially designed to help the user to learn an alphabet";
|
||||||
maintainers = with maintainers; [ freezeboy ];
|
maintainers = with maintainers; [ freezeboy ];
|
||||||
license = licenses.gpl2Plus;
|
license = licenses.gpl2Plus;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
mkDerivation {
|
mkDerivation {
|
||||||
pname = "kturtle";
|
pname = "kturtle";
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://kde.org/applications/en/utilities/org.kde.kturtle";
|
homepage = "https://invent.kde.org/education/kturtle";
|
||||||
description = "An educational programming environment for learning how to program";
|
description = "An educational programming environment for learning how to program";
|
||||||
maintainers = with maintainers; [ freezeboy ];
|
maintainers = with maintainers; [ freezeboy ];
|
||||||
license = licenses.gpl2Plus;
|
license = licenses.gpl2Plus;
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
{ lib, fetchFromGitHub
|
{ lib, fetchFromGitHub
|
||||||
, meson, ninja, pkg-config, wrapGAppsHook
|
, meson, ninja, pkg-config, wrapGAppsHook
|
||||||
, desktop-file-utils, gsettings-desktop-schemas, libnotify, libhandy
|
, desktop-file-utils, gsettings-desktop-schemas, libnotify, libhandy, webkitgtk
|
||||||
, python3Packages, gettext
|
, python3Packages, gettext
|
||||||
, appstream-glib, gdk-pixbuf, glib, gobject-introspection, gspell, gtk3
|
, appstream-glib, gdk-pixbuf, glib, gobject-introspection, gspell, gtk3, gnome
|
||||||
, steam-run, xdg-utils, pciutils, cabextract, wineWowPackages
|
, steam-run, xdg-utils, pciutils, cabextract, wineWowPackages
|
||||||
|
, freetype, p7zip, gamemode
|
||||||
}:
|
}:
|
||||||
|
|
||||||
python3Packages.buildPythonApplication rec {
|
python3Packages.buildPythonApplication rec {
|
||||||
pname = "bottles";
|
pname = "bottles";
|
||||||
version = "2021.7.28-treviso-2";
|
version = "2021.12.28-treviso";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "bottlesdevs";
|
owner = "bottlesdevs";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "0kvwcajm9izvkwfg7ir7bks39bpc665idwa8mc8d536ajyjriysn";
|
sha256 = "lZbSLLBg7XM6PuOmu5rJ15dg+QHHRcjijRYE6u3WT9Y=";
|
||||||
};
|
};
|
||||||
|
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
|
@ -41,10 +42,13 @@ python3Packages.buildPythonApplication rec {
|
||||||
gtk3
|
gtk3
|
||||||
libhandy
|
libhandy
|
||||||
libnotify
|
libnotify
|
||||||
|
webkitgtk
|
||||||
|
gnome.adwaita-icon-theme
|
||||||
];
|
];
|
||||||
|
|
||||||
propagatedBuildInputs = with python3Packages; [
|
propagatedBuildInputs = with python3Packages; [
|
||||||
pyyaml
|
pyyaml
|
||||||
|
pytoml
|
||||||
requests
|
requests
|
||||||
pycairo
|
pycairo
|
||||||
pygobject3
|
pygobject3
|
||||||
|
@ -53,12 +57,16 @@ python3Packages.buildPythonApplication rec {
|
||||||
gst-python
|
gst-python
|
||||||
liblarch
|
liblarch
|
||||||
patool
|
patool
|
||||||
|
markdown
|
||||||
] ++ [
|
] ++ [
|
||||||
steam-run
|
steam-run
|
||||||
xdg-utils
|
xdg-utils
|
||||||
pciutils
|
pciutils
|
||||||
cabextract
|
cabextract
|
||||||
wineWowPackages.minimal
|
wineWowPackages.minimal
|
||||||
|
freetype
|
||||||
|
p7zip
|
||||||
|
gamemode # programs.gamemode.enable
|
||||||
];
|
];
|
||||||
|
|
||||||
format = "other";
|
format = "other";
|
||||||
|
@ -66,13 +74,9 @@ python3Packages.buildPythonApplication rec {
|
||||||
dontWrapGApps = true; # prevent double wrapping
|
dontWrapGApps = true; # prevent double wrapping
|
||||||
|
|
||||||
preConfigure = ''
|
preConfigure = ''
|
||||||
substituteInPlace build-aux/meson/postinstall.py \
|
patchShebangs build-aux/meson/postinstall.py
|
||||||
--replace "'update-desktop-database'" "'${desktop-file-utils}/bin/update-desktop-database'"
|
substituteInPlace src/backend/runner.py \
|
||||||
substituteInPlace src/runner.py \
|
--replace "{Paths.runners}" "${steam-run}/bin/steam-run {Paths.runners}"
|
||||||
--replace " {runner}" " ${steam-run}/bin/steam-run {runner}" \
|
|
||||||
--replace " {dxvk_setup}" " ${steam-run}/bin/steam-run {dxvk_setup}"
|
|
||||||
substituteInPlace src/runner_utilities.py \
|
|
||||||
--replace " {runner}" " ${steam-run}/bin/steam-run {runner}" \
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
preFixup = ''
|
preFixup = ''
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "charm";
|
pname = "charm";
|
||||||
version = "0.9.0";
|
version = "0.9.2";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "charmbracelet";
|
owner = "charmbracelet";
|
||||||
repo = "charm";
|
repo = "charm";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "1q5c2qka4srqj82f50iwmcj2j0yw2msz5dmrx2avqppp3fyi9jz3";
|
sha256 = "sha256-5WNkD+YfmQHGAWWfD9/ZEHnHPT0Ejm9Nz+/mn8xvU4U=";
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "1xycgzx706kyz37z3517p98129iy7py7zdizz34k38fvfpila5q5";
|
vendorSha256 = "sha256-TncVMDeZ8+Wuv1o0Cjks3Ve1OsO+WXH9mClC6GNaSas=";
|
||||||
|
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
|
|
||||||
|
|
|
@ -20,13 +20,13 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "dbeaver";
|
pname = "dbeaver";
|
||||||
version = "21.3.1"; # When updating also update fetchedMavenDeps.sha256
|
version = "21.3.2"; # When updating also update fetchedMavenDeps.sha256
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "dbeaver";
|
owner = "dbeaver";
|
||||||
repo = "dbeaver";
|
repo = "dbeaver";
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "ePy3uS+LpyDzweLocSk3O/G2zFPISKbMbci9fdELrpE=";
|
sha256 = "SifnnzuETFKtnEwLjJtB7CV2QZaToex3MjKGuiShlwo=";
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchedMavenDeps = stdenv.mkDerivation {
|
fetchedMavenDeps = stdenv.mkDerivation {
|
||||||
|
@ -52,7 +52,7 @@ stdenv.mkDerivation rec {
|
||||||
dontFixup = true;
|
dontFixup = true;
|
||||||
outputHashAlgo = "sha256";
|
outputHashAlgo = "sha256";
|
||||||
outputHashMode = "recursive";
|
outputHashMode = "recursive";
|
||||||
outputHash = "7Sm1hAoi5xc4MLONOD8ySLLkpao0qmlMRRva/8zR210=";
|
outputHash = "grSFtkohTlLtK8qE4A4wVppC6UHcyaXRQlGnrOmQDC4=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ lib, fetchFromGitHub, gtk3, pythonPackages, intltool, gexiv2,
|
{ lib, fetchFromGitHub, gtk3, pythonPackages, intltool, gexiv2,
|
||||||
pango, gobject-introspection, wrapGAppsHook, gettext,
|
pango, gobject-introspection, wrapGAppsHook, gettext,
|
||||||
# Optional packages:
|
# Optional packages:
|
||||||
enableOSM ? true, osm-gps-map,
|
enableOSM ? true, osm-gps-map, glib-networking,
|
||||||
enableGraphviz ? true, graphviz,
|
enableGraphviz ? true, graphviz,
|
||||||
enableGhostscript ? true, ghostscript
|
enableGhostscript ? true, ghostscript
|
||||||
}:
|
}:
|
||||||
|
@ -15,7 +15,7 @@ in buildPythonApplication rec {
|
||||||
nativeBuildInputs = [ wrapGAppsHook intltool gettext ];
|
nativeBuildInputs = [ wrapGAppsHook intltool gettext ];
|
||||||
buildInputs = [ gtk3 gobject-introspection pango gexiv2 ]
|
buildInputs = [ gtk3 gobject-introspection pango gexiv2 ]
|
||||||
# Map support
|
# Map support
|
||||||
++ lib.optional enableOSM osm-gps-map
|
++ lib.optionals enableOSM [ osm-gps-map glib-networking ]
|
||||||
# Graphviz support
|
# Graphviz support
|
||||||
++ lib.optional enableGraphviz graphviz
|
++ lib.optional enableGraphviz graphviz
|
||||||
# Ghostscript support
|
# Ghostscript support
|
||||||
|
|
40
third_party/nixpkgs/pkgs/applications/misc/inherd-quake/default.nix
vendored
Normal file
40
third_party/nixpkgs/pkgs/applications/misc/inherd-quake/default.nix
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{ lib
|
||||||
|
, fetchFromGitHub
|
||||||
|
, rustPlatform
|
||||||
|
, pkg-config
|
||||||
|
, openssl
|
||||||
|
, stdenv
|
||||||
|
, CoreServices
|
||||||
|
, Security
|
||||||
|
}:
|
||||||
|
|
||||||
|
rustPlatform.buildRustPackage rec {
|
||||||
|
pname = "inherd-quake";
|
||||||
|
version = "0.3.0";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "phodal";
|
||||||
|
repo = "quake";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "1f7k68g18g3dpnrsmhgmz753bly1i3f4lmsljiyp9ap0c6w8ahgg";
|
||||||
|
};
|
||||||
|
|
||||||
|
cargoSha256 = "17q9sjypa331gdfvmx1kbcbvnj34rnsf37b9rnji4jrqfysgrs5w";
|
||||||
|
|
||||||
|
nativeBuildInputs = [ pkg-config ];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
openssl
|
||||||
|
] ++ lib.optionals stdenv.isDarwin [
|
||||||
|
CoreServices
|
||||||
|
Security
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A knowledge management meta-framework for geeks";
|
||||||
|
homepage = "https://github.com/phodal/quake";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = [ maintainers.elliot ];
|
||||||
|
mainProgram = "quake";
|
||||||
|
};
|
||||||
|
}
|
|
@ -50,5 +50,6 @@ appimageTools.wrapType2 rec {
|
||||||
license = licenses.mit;
|
license = licenses.mit;
|
||||||
maintainers = with maintainers; [ nh2 ];
|
maintainers = with maintainers; [ nh2 ];
|
||||||
platforms = [ "x86_64-linux" ];
|
platforms = [ "x86_64-linux" ];
|
||||||
|
mainProgram = "marktext";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
, itstool
|
, itstool
|
||||||
, libadwaita
|
, libadwaita
|
||||||
, librsvg
|
, librsvg
|
||||||
, meson
|
, meson_0_60
|
||||||
, ninja
|
, ninja
|
||||||
, pkg-config
|
, pkg-config
|
||||||
, poppler_gi
|
, poppler_gi
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
python3.pkgs.buildPythonApplication rec {
|
python3.pkgs.buildPythonApplication rec {
|
||||||
pname = "metadata-cleaner";
|
pname = "metadata-cleaner";
|
||||||
version = "2.0.1";
|
version = "2.1.3";
|
||||||
|
|
||||||
format = "other";
|
format = "other";
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ python3.pkgs.buildPythonApplication rec {
|
||||||
owner = "rmnvgr";
|
owner = "rmnvgr";
|
||||||
repo = "metadata-cleaner";
|
repo = "metadata-cleaner";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-iTKs3DEZSzqRARXJKPPygvCS5JNUMbQBkfjacwd168Y=";
|
hash = "sha256-9sLjgqqQBXcudlBRmqAwWcWMUXoIUyAK272zaNKbJNY=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
@ -35,7 +35,7 @@ python3.pkgs.buildPythonApplication rec {
|
||||||
glib
|
glib
|
||||||
gtk4
|
gtk4
|
||||||
itstool
|
itstool
|
||||||
meson
|
meson_0_60
|
||||||
ninja
|
ninja
|
||||||
pkg-config
|
pkg-config
|
||||||
wrapGAppsHook
|
wrapGAppsHook
|
||||||
|
|
25
third_party/nixpkgs/pkgs/applications/misc/neo/default.nix
vendored
Normal file
25
third_party/nixpkgs/pkgs/applications/misc/neo/default.nix
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{ lib, stdenv, fetchurl, ncurses }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "neo";
|
||||||
|
version = "0.6";
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
url = "https://github.com/st3w/neo/releases/download/v${version}/neo-${version}.tar.gz";
|
||||||
|
sha256 = "sha256-skXLT1td4dGdsu+wbX44Z2u5sDEOKXYVVys4Q6RayIk=";
|
||||||
|
};
|
||||||
|
|
||||||
|
buildInputs = [ ncurses ];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = ''Simulates the digital rain from "The Matrix"'';
|
||||||
|
license = licenses.gpl3Plus;
|
||||||
|
longDescription = ''
|
||||||
|
neo recreates the digital rain effect from "The Matrix". Streams of random
|
||||||
|
characters will endlessly scroll down your terminal screen.
|
||||||
|
'';
|
||||||
|
homepage = "https://github.com/st3w/neo";
|
||||||
|
platforms = ncurses.meta.platforms;
|
||||||
|
maintainers = [ maintainers.abbe ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
{ stdenv, lib, fetchFromGitHub, cmake, copyDesktopItems, makeDesktopItem, pkg-config, wrapGAppsHook
|
{ stdenv, lib, fetchFromGitHub, cmake, copyDesktopItems, makeDesktopItem, pkg-config, wrapGAppsHook
|
||||||
, boost, cereal, cgal_5, curl, dbus, eigen, expat, glew, glib, gmp, gtest, gtk3, hicolor-icon-theme
|
, boost, cereal, cgal_5, curl, dbus, eigen, expat, glew, glib, gmp, gtest, gtk3, hicolor-icon-theme
|
||||||
, ilmbase, libpng, mpfr, nlopt, openvdb, pcre, qhull, systemd, tbb, wxGTK31-gtk3, xorg
|
, ilmbase, libpng, mpfr, nlopt, openvdb, pcre, qhull, systemd, tbb, wxGTK31-gtk3, xorg, fetchpatch
|
||||||
}:
|
}:
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "prusa-slicer";
|
pname = "prusa-slicer";
|
||||||
version = "2.3.3";
|
version = "2.4.0";
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
cmake
|
cmake
|
||||||
|
@ -38,9 +38,19 @@ stdenv.mkDerivation rec {
|
||||||
xorg.libX11
|
xorg.libX11
|
||||||
] ++ checkInputs;
|
] ++ checkInputs;
|
||||||
|
|
||||||
|
patches = [
|
||||||
|
# Fix detection of TBB, see https://github.com/prusa3d/PrusaSlicer/issues/6355
|
||||||
|
(fetchpatch {
|
||||||
|
url = "https://github.com/prusa3d/PrusaSlicer/commit/76f4d6fa98bda633694b30a6e16d58665a634680.patch";
|
||||||
|
sha256 = "1r806ycp704ckwzgrw1940hh1l6fpz0k1ww3p37jdk6mygv53nv6";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
doCheck = true;
|
doCheck = true;
|
||||||
checkInputs = [ gtest ];
|
checkInputs = [ gtest ];
|
||||||
|
|
||||||
|
separateDebugInfo = true;
|
||||||
|
|
||||||
# The build system uses custom logic - defined in
|
# The build system uses custom logic - defined in
|
||||||
# cmake/modules/FindNLopt.cmake in the package source - for finding the nlopt
|
# cmake/modules/FindNLopt.cmake in the package source - for finding the nlopt
|
||||||
# library, which doesn't pick up the package in the nix store. We
|
# library, which doesn't pick up the package in the nix store. We
|
||||||
|
@ -56,11 +66,6 @@ stdenv.mkDerivation rec {
|
||||||
NIX_LDFLAGS = "-ludev";
|
NIX_LDFLAGS = "-ludev";
|
||||||
|
|
||||||
prePatch = ''
|
prePatch = ''
|
||||||
# In nix ioctls.h isn't available from the standard kernel-headers package
|
|
||||||
# like in other distributions. The copy in glibc seems to be identical to the
|
|
||||||
# one in the kernel though, so we use that one instead.
|
|
||||||
sed -i 's|"/usr/include/asm-generic/ioctls.h"|<asm-generic/ioctls.h>|g' src/libslic3r/GCodeSender.cpp
|
|
||||||
|
|
||||||
# Since version 2.5.0 of nlopt we need to link to libnlopt, as libnlopt_cxx
|
# Since version 2.5.0 of nlopt we need to link to libnlopt, as libnlopt_cxx
|
||||||
# now seems to be integrated into the main lib.
|
# now seems to be integrated into the main lib.
|
||||||
sed -i 's|nlopt_cxx|nlopt|g' cmake/modules/FindNLopt.cmake
|
sed -i 's|nlopt_cxx|nlopt|g' cmake/modules/FindNLopt.cmake
|
||||||
|
@ -69,7 +74,7 @@ stdenv.mkDerivation rec {
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "prusa3d";
|
owner = "prusa3d";
|
||||||
repo = "PrusaSlicer";
|
repo = "PrusaSlicer";
|
||||||
sha256 = "0w0synqi3iz9aigsgv6x1c6sg123fasbx19h4w3ic1l48r8qmpwm";
|
sha256 = "1mb7v0khrmsgy3inmh4mjn709jlhx422kvbnrhsqziph2wwak9bz";
|
||||||
rev = "version_${version}";
|
rev = "version_${version}";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ let
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
patches = null;
|
||||||
|
|
||||||
# We don't need PS overrides anymore, and gcode-viewer is embedded in the binary.
|
# We don't need PS overrides anymore, and gcode-viewer is embedded in the binary.
|
||||||
postInstall = null;
|
postInstall = null;
|
||||||
separateDebugInfo = true;
|
separateDebugInfo = true;
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "skate";
|
pname = "skate";
|
||||||
version = "0.1.2";
|
version = "0.1.3";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "charmbracelet";
|
owner = "charmbracelet";
|
||||||
repo = "skate";
|
repo = "skate";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-Z+7unYmwPLOhJAMAhMwjapAmslTNxmP01myjgEOBfu8=";
|
sha256 = "sha256-rUOFx0ebZs3xmsSz9oFvjINaHp9gIe7E/5UoJJ47aZc=";
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "sha256-CdYyiUiy2q2boEHjdXkgRzVI+6fEb+fBrlInl6IrFjk=";
|
vendorSha256 = "sha256-3+KXirGwZvPhqCeglPqHJ9wEt6naJiRE3TAX7/jxJpk=";
|
||||||
|
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,44 @@
|
||||||
{ lib, stdenv, fetchFromGitLab, ocaml, findlib, ocf, ptime,
|
{ lib, buildDunePackage, fetchFromGitLab, ocaml
|
||||||
uutf, uri, ppx_blob, xtmpl, ocaml_lwt, higlo, omd
|
, fmt, lwt_ppx, menhir, ocf_ppx, ppx_blob, xtmpl_ppx
|
||||||
|
, dune-build-info, dune-site, higlo, logs, lwt, ocf, ptime, uri, uutf, xtmpl
|
||||||
}:
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
if lib.versionAtLeast ocaml.version "4.13"
|
||||||
|
then throw "stog is not available for OCaml ${ocaml.version}"
|
||||||
|
else
|
||||||
|
|
||||||
|
buildDunePackage rec {
|
||||||
pname = "stog";
|
pname = "stog";
|
||||||
version = "0.18.0";
|
version = "0.20.0";
|
||||||
|
useDune2 = true;
|
||||||
|
minimalOCamlVersion = "4.12";
|
||||||
src = fetchFromGitLab {
|
src = fetchFromGitLab {
|
||||||
domain = "framagit.org";
|
domain = "framagit.org";
|
||||||
owner = "zoggy";
|
owner = "zoggy";
|
||||||
repo = "stog";
|
repo = "stog";
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "154gl3ljxqlw8wz1vmsyv8180igrl5bjq0wir7ybrnzq2cdflkv0";
|
sha256 = "sha256:0krj5w4y05bcfx7hk9blmap8avl31gp7yi01lpqzs6ync23mvm0x";
|
||||||
};
|
};
|
||||||
|
|
||||||
buildInputs = [ ocaml uutf ];
|
buildInputs = [ fmt lwt_ppx menhir ocf_ppx ppx_blob xtmpl_ppx ];
|
||||||
propagatedBuildInputs = [ findlib omd ppx_blob ocf ptime uri xtmpl ocaml_lwt higlo ];
|
propagatedBuildInputs = [
|
||||||
|
dune-build-info
|
||||||
createFindlibDestdir = true;
|
dune-site
|
||||||
|
higlo
|
||||||
patches = [ ./install.patch ./uri.patch ];
|
logs
|
||||||
|
lwt
|
||||||
|
ocf
|
||||||
|
ppx_blob
|
||||||
|
ptime
|
||||||
|
uri
|
||||||
|
uutf
|
||||||
|
xtmpl
|
||||||
|
];
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
description = "XML documents and web site compiler";
|
description = "XML documents and web site compiler";
|
||||||
homepage = "https://www.good-eris.net/stog";
|
homepage = "https://www.good-eris.net/stog";
|
||||||
license = licenses.lgpl3;
|
license = licenses.lgpl3;
|
||||||
platforms = ocaml.meta.platforms or [];
|
|
||||||
maintainers = with maintainers; [ regnat ];
|
maintainers = with maintainers; [ regnat ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
diff --git a/src/Makefile b/src/Makefile
|
|
||||||
index 736dd037..79a85b9c 100644
|
|
||||||
--- a/src/Makefile
|
|
||||||
+++ b/src/Makefile
|
|
||||||
@@ -431,11 +431,12 @@ install-lib:
|
|
||||||
install-share:
|
|
||||||
|
|
||||||
install-bin:
|
|
||||||
+ mkdir $(out)/bin
|
|
||||||
$(CP) $(MAIN) $(MAIN_BYTE) $(TMPL) $(TMPL_BYTE) \
|
|
||||||
$(SERVER) $(SERVER_BYTE) $(OCAML_SESSION) \
|
|
||||||
$(MK_STOG) $(MK_STOG_BYTE) $(MK_STOG_OCAML) \
|
|
||||||
$(LATEX2STOG) $(LATEX2STOG_BYTE) \
|
|
||||||
- `dirname \`which $(OCAMLC)\``/
|
|
||||||
+ $(out)/bin
|
|
||||||
|
|
||||||
uninstall: uninstall-lib uninstall-share uninstall-bin
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
diff --git a/src/stog_url.ml b/src/stog_url.ml
|
|
||||||
index 5d30a43f..c67bfc36 100644
|
|
||||||
--- a/src/stog_url.ml
|
|
||||||
+++ b/src/stog_url.ml
|
|
||||||
@@ -40,7 +40,7 @@ let of_string s =
|
|
||||||
with _ ->
|
|
||||||
failwith (Printf.sprintf "Malformed URL %S" s)
|
|
||||||
;;
|
|
||||||
-let to_string = Uri.to_string ;;
|
|
||||||
+let to_string u = Uri.to_string u;;
|
|
||||||
|
|
||||||
let path url =
|
|
||||||
let l =
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "timew-sync-server";
|
pname = "timew-sync-server";
|
||||||
version = "1.0.0";
|
version = "1.1.0";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "timewarrior-synchronize";
|
owner = "timewarrior-synchronize";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "041j618c2bcryhgi2j2w5zlfcxcklgbir2xj3px4w7jxbbg6p68n";
|
sha256 = "GaDcnPJBcDJ3AQaHzifDgdl0QT4GSbAOIqp4RrAcO3M=";
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "0wbd4cpswgbr839sk8qwly8gjq4lqmq448m624akll192mzm9wj7";
|
vendorSha256 = "iROqiRWkHG6N6kivUmgmu6sg14JDdG4f98BdR7CL1gs=";
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://github.com/timewarrior-synchronize/timew-sync-server";
|
homepage = "https://github.com/timewarrior-synchronize/timew-sync-server";
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "amfora";
|
pname = "amfora";
|
||||||
version = "1.9.0";
|
version = "1.9.2";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "makeworld-the-better-one";
|
owner = "makeworld-the-better-one";
|
||||||
repo = "amfora";
|
repo = "amfora";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-Vj5aFSpyC7X9e9A9r4FAI6a0U8dx8uj7bpAFrQjLSzo=";
|
sha256 = "sha256-93xNzYPoy8VsbY2JyvDXt4J/gIbI2wzrCD83JUaP150=";
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "sha256-XtiGj2Tr6sSBduIjBspeZpYaSTd6x6EVf3VEVMXDAD0=";
|
vendorSha256 = "sha256-XtiGj2Tr6sSBduIjBspeZpYaSTd6x6EVf3VEVMXDAD0=";
|
||||||
|
|
|
@ -297,10 +297,17 @@ stdenv.mkDerivation rec {
|
||||||
cp -u --no-preserve=mode,owner "$TBB_IN_STORE/TorBrowser/Data/Browser/profile.default/bookmarks.html" \
|
cp -u --no-preserve=mode,owner "$TBB_IN_STORE/TorBrowser/Data/Browser/profile.default/bookmarks.html" \
|
||||||
"\$HOME/TorBrowser/Data/Browser/profile.default/bookmarks.html"
|
"\$HOME/TorBrowser/Data/Browser/profile.default/bookmarks.html"
|
||||||
|
|
||||||
|
# Clear some files if the last known store path is different from the new one
|
||||||
|
: "\''${KNOWN_STORE_PATH:=\$HOME/known-store-path}"
|
||||||
|
if ! [ "\$KNOWN_STORE_PATH" -ef $out ]; then
|
||||||
|
echo "Cleanup files with outdated store references"
|
||||||
|
ln -Tsf $out "\$KNOWN_STORE_PATH"
|
||||||
|
|
||||||
# Clear out some files that tend to capture store references but are
|
# Clear out some files that tend to capture store references but are
|
||||||
# easily generated by firefox at startup.
|
# easily generated by firefox at startup.
|
||||||
rm -f "\$HOME/TorBrowser/Data/Browser/profile.default"/{addonStartup.json.lz4,compatibility.ini,extensions.ini,extensions.json}
|
rm -f "\$HOME/TorBrowser/Data/Browser/profile.default"/{addonStartup.json.lz4,compatibility.ini,extensions.ini,extensions.json}
|
||||||
rm -f "\$HOME/TorBrowser/Data/Browser/profile.default"/startupCache/*
|
rm -f "\$HOME/TorBrowser/Data/Browser/profile.default"/startupCache/*
|
||||||
|
fi
|
||||||
|
|
||||||
# XDG
|
# XDG
|
||||||
: "\''${XDG_RUNTIME_DIR:=/run/user/\$(id -u)}"
|
: "\''${XDG_RUNTIME_DIR:=/run/user/\$(id -u)}"
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "k9s";
|
pname = "k9s";
|
||||||
version = "0.25.12";
|
version = "0.25.18";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "derailed";
|
owner = "derailed";
|
||||||
repo = "k9s";
|
repo = "k9s";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-S+roKkAtiGJmp/MHFeB+8mLQDL9okzLuJW6DMz3dQDk=";
|
sha256 = "sha256-iUhMPtFX7qFULegiyhlT4aG9q3deZ8aRqyEcbZ9jY/s=";
|
||||||
};
|
};
|
||||||
|
|
||||||
ldflags = [
|
ldflags = [
|
||||||
|
|
33
third_party/nixpkgs/pkgs/applications/networking/cluster/kubergrunt/default.nix
vendored
Normal file
33
third_party/nixpkgs/pkgs/applications/networking/cluster/kubergrunt/default.nix
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{ buildGoModule, lib, fetchFromGitHub }:
|
||||||
|
|
||||||
|
buildGoModule rec {
|
||||||
|
pname = "kubergrunt";
|
||||||
|
version = "0.7.11";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "gruntwork-io";
|
||||||
|
repo = "kubergrunt";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "1224ssqdz9ak0vylyfbr9c2w0yfdp4hw9jh99qmfi2j5nhw9kzcc";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorSha256 = "1hbb3hn8mzz9h9p1rl35izz3l6c2rqsg8aq6dgpbpsf5krp3zs3v";
|
||||||
|
|
||||||
|
# Disable tests since it requires network access and relies on the
|
||||||
|
# presence of certain AWS infrastructure
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
runVend = true;
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
# The binary is named kubergrunt
|
||||||
|
mv $out/bin/cmd $out/bin/kubergrunt
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Collection of commands to fill in the gaps between Terraform, Helm, and Kubectl";
|
||||||
|
homepage = "https://github.com/gruntwork-io/kubergrunt";
|
||||||
|
license = licenses.asl20;
|
||||||
|
maintainers = with maintainers; [ psibi ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -46,7 +46,7 @@ let
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
description = "Apache Spark is a fast and general engine for large-scale data processing";
|
description = "Apache Spark is a fast and general engine for large-scale data processing";
|
||||||
homepage = "http://spark.apache.org";
|
homepage = "https://spark.apache.org/";
|
||||||
license = lib.licenses.asl20;
|
license = lib.licenses.asl20;
|
||||||
platforms = lib.platforms.all;
|
platforms = lib.platforms.all;
|
||||||
maintainers = with maintainers; [ thoughtpolice offline kamilchm illustris ];
|
maintainers = with maintainers; [ thoughtpolice offline kamilchm illustris ];
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
# https://github.com/dmacvicar/terraform-provider-libvirt/tree/main/examples
|
# https://github.com/dmacvicar/terraform-provider-libvirt/tree/main/examples
|
||||||
|
|
||||||
let
|
let
|
||||||
sha256 = "sha256-8GGPd0+qdw7s4cr0RgLoS0Cu4C+RAuuboZzTyYN/kq8=";
|
sha256 = "sha256-1l+ARrXHxtSdnQfYV/6gw3BYHVH8NN4pi+Ttk1nwF88=";
|
||||||
vendorSha256 = "sha256-fpO2sGM+VUKLmdfJ9CQfTFnCfxVTK2m9Sirj9oerD/I=";
|
vendorSha256 = "sha256-OJa8pQgf5PlECZZkFV9fyCOdh6CrregY1BWycx7JPFE=";
|
||||||
version = "0.6.11";
|
version = "0.6.12";
|
||||||
in buildGoModule {
|
in buildGoModule {
|
||||||
inherit version;
|
inherit version;
|
||||||
inherit vendorSha256;
|
inherit vendorSha256;
|
||||||
|
@ -50,7 +50,6 @@ in buildGoModule {
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://github.com/dmacvicar/terraform-provider-libvirt";
|
homepage = "https://github.com/dmacvicar/terraform-provider-libvirt";
|
||||||
description = "Terraform provider for libvirt";
|
description = "Terraform provider for libvirt";
|
||||||
platforms = platforms.linux;
|
|
||||||
license = licenses.asl20;
|
license = licenses.asl20;
|
||||||
maintainers = with maintainers; [ mic92 ];
|
maintainers = with maintainers; [ mic92 ];
|
||||||
};
|
};
|
||||||
|
|
|
@ -1129,10 +1129,10 @@
|
||||||
"owner": "hashicorp",
|
"owner": "hashicorp",
|
||||||
"provider-source-address": "registry.terraform.io/hashicorp/vault",
|
"provider-source-address": "registry.terraform.io/hashicorp/vault",
|
||||||
"repo": "terraform-provider-vault",
|
"repo": "terraform-provider-vault",
|
||||||
"rev": "v3.0.1",
|
"rev": "v3.1.1",
|
||||||
"sha256": "0ppx8kc4zf0yp09vbkmj875sqvklbx0p8a1ganpzdm3462zskra4",
|
"sha256": "15fwc0sfdpcl85194gq6r97y18ggh61wbyh6lq7nrprwn2xvjch9",
|
||||||
"vendorSha256": "03l8bk9jsqf4c7gv0hs1rli7wmlcvpdxmxhra9vndnz6g0jvkvyx",
|
"vendorSha256": "1q2yfmg6g3bl6h0vzanz7874xc4g7ggmysh2dqryijvr4kccnari",
|
||||||
"version": "3.0.1"
|
"version": "3.1.1"
|
||||||
},
|
},
|
||||||
"vcd": {
|
"vcd": {
|
||||||
"owner": "terraform-providers",
|
"owner": "terraform-providers",
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "terragrunt";
|
pname = "terragrunt";
|
||||||
version = "0.35.14";
|
version = "0.35.16";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "gruntwork-io";
|
owner = "gruntwork-io";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-bK1xWzIowNF5gS4feRkCbTB1je/ttbmrqweaHplk8n8=";
|
sha256 = "sha256-m32QhQUG3Dkh0odfqYhNmJ5Rrt0qf5wCvxePPusyRyI=";
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "sha256-tNgEepKqwiqXhmoRCIEg7VJw7Y0TGt+R+6dZzd8aECg=";
|
vendorSha256 = "sha256-tNgEepKqwiqXhmoRCIEg7VJw7Y0TGt+R+6dZzd8aECg=";
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
|
|
||||||
rustPlatform.buildRustPackage rec {
|
rustPlatform.buildRustPackage rec {
|
||||||
pname = "newsboat";
|
pname = "newsboat";
|
||||||
version = "2.25";
|
version = "2.26";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "newsboat";
|
owner = "newsboat";
|
||||||
repo = "newsboat";
|
repo = "newsboat";
|
||||||
rev = "r${version}";
|
rev = "r${version}";
|
||||||
sha256 = "sha256-TAnGDxTKYl4niouS6nYdJDaIngAPsPHr9Bw9L3cR2Xk=";
|
hash = "sha256-VFeKj8X7gEyxsdsOK6UYJ6xB24gsuzb1Wm4GK5AJCHc=";
|
||||||
};
|
};
|
||||||
|
|
||||||
cargoSha256 = "sha256-MxoyYBLbrCuLVa0p8JrYKSKu2oFPnXMwab42lhhAu48=";
|
cargoHash = "sha256-pr/Vzm321/uX4fIGt3kuWrtcgsnDRbeK3AvNO19NDwQ=";
|
||||||
|
|
||||||
# TODO: Check if that's still needed
|
# TODO: Check if that's still needed
|
||||||
postPatch = lib.optionalString stdenv.isDarwin ''
|
postPatch = lib.optionalString stdenv.isDarwin ''
|
||||||
|
@ -34,9 +34,6 @@ rustPlatform.buildRustPackage rec {
|
||||||
make prefix="$out"
|
make prefix="$out"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# TODO: Check if that's still needed
|
|
||||||
NIX_CFLAGS_COMPILE = lib.optionalString stdenv.isDarwin " -Wno-error=format-security";
|
|
||||||
|
|
||||||
# https://github.com/NixOS/nixpkgs/pull/98471#issuecomment-703100014 . We set
|
# https://github.com/NixOS/nixpkgs/pull/98471#issuecomment-703100014 . We set
|
||||||
# these for all platforms, since upstream's gettext crate behavior might
|
# these for all platforms, since upstream's gettext crate behavior might
|
||||||
# change in the future.
|
# change in the future.
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
with lib;
|
with lib;
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "bitlbee-mastodon";
|
pname = "bitlbee-mastodon";
|
||||||
version = "1.4.4";
|
version = "1.4.5";
|
||||||
|
|
||||||
src = fetchgit {
|
src = fetchgit {
|
||||||
url = "https://alexschroeder.ch/cgit/bitlbee-mastodon";
|
url = "https://alexschroeder.ch/cgit/bitlbee-mastodon";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "0a8196pyr6bjnqg82zn7jdhiv7xsg4npbpzalla1i2h99j30q8pk";
|
sha256 = "sha256-8vmq/YstuBYUxe00P4NrxD/eMYI++R9uvn1sCcMTr7I=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ autoreconfHook pkg-config ];
|
nativeBuildInputs = [ autoreconfHook pkg-config ];
|
||||||
|
|
|
@ -4,7 +4,7 @@ with ocamlPackages;
|
||||||
|
|
||||||
buildDunePackage rec {
|
buildDunePackage rec {
|
||||||
pname = "jackline";
|
pname = "jackline";
|
||||||
version = "unstable-2021-08-10";
|
version = "unstable-2021-12-28";
|
||||||
|
|
||||||
minimumOCamlVersion = "4.08";
|
minimumOCamlVersion = "4.08";
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ buildDunePackage rec {
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "hannesm";
|
owner = "hannesm";
|
||||||
repo = "jackline";
|
repo = "jackline";
|
||||||
rev = "73d87e9a62d534566bb0fbe64990d32d75487f11";
|
rev = "ca1012098d123c555e9fa5244466d2e009521700";
|
||||||
sha256 = "0wk574rqfg2vqz27nasxzwf67x51pj5fgl4vkc27r741dg4q6c5a";
|
sha256 = "1j1azskcdrp4g44rv3a4zylkzbzpcs23zzzrx94llbgssw6cd9ih";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInpts = [
|
nativeBuildInpts = [
|
||||||
|
|
|
@ -4,11 +4,11 @@ let
|
||||||
in
|
in
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "rocketchat-desktop";
|
pname = "rocketchat-desktop";
|
||||||
version = "3.7.1";
|
version = "3.7.2";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://github.com/RocketChat/Rocket.Chat.Electron/releases/download/${version}/rocketchat_${version}_amd64.deb";
|
url = "https://github.com/RocketChat/Rocket.Chat.Electron/releases/download/${version}/rocketchat_${version}_amd64.deb";
|
||||||
sha256 = "1l4g0y7kb569w1i3c1bq6m0p9wykrf7k6a59j5cvnkl1b9h8mj4p";
|
sha256 = "sha256-sSSi8L5WXFAc9yRDZ2usWmh6F06/1RMbJInQ4/OORnI=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
|
|
@ -6,23 +6,24 @@ with lib;
|
||||||
|
|
||||||
perlPackages.buildPerlPackage rec {
|
perlPackages.buildPerlPackage rec {
|
||||||
pname = "convos";
|
pname = "convos";
|
||||||
version = "6.26";
|
version = "6.42";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "convos-chat";
|
owner = "convos-chat";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "1wh3ryhd4b7nanh0yp2nycmhky5afw8lpfx34858p6wfimsv9794";
|
sha256 = "sha256-W7ZVZUCNllpFIQpNz2m/8VFOXDZfuppB+g3qibY6wt8=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ makeWrapper ]
|
nativeBuildInputs = [ makeWrapper ]
|
||||||
++ optional stdenv.isDarwin [ shortenPerlShebang ];
|
++ optional stdenv.isDarwin [ shortenPerlShebang ];
|
||||||
|
|
||||||
buildInputs = with perlPackages; [
|
buildInputs = with perlPackages; [
|
||||||
CryptEksblowfish FileHomeDir FileReadBackwards HTTPAcceptLanguage
|
CryptPassphrase CryptPassphraseArgon2 CryptPassphraseBcrypt
|
||||||
|
FileHomeDir FileReadBackwards HTTPAcceptLanguage
|
||||||
IOSocketSSL IRCUtils JSONValidator LinkEmbedder ModuleInstall
|
IOSocketSSL IRCUtils JSONValidator LinkEmbedder ModuleInstall
|
||||||
Mojolicious MojoliciousPluginOpenAPI MojoliciousPluginWebpack
|
Mojolicious MojoliciousPluginOpenAPI MojoliciousPluginSyslog MojoliciousPluginWebpack
|
||||||
ParseIRC TextMarkdown TimePiece UnicodeUTF8
|
ParseIRC TextMarkdownHoedown TimePiece UnicodeUTF8
|
||||||
CpanelJSONXS EV
|
CpanelJSONXS EV
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
, heimdal, krb5, libsoup, libvorbis, speex, openssl, zlib, xorg, pango, gtk2
|
, heimdal, krb5, libsoup, libvorbis, speex, openssl, zlib, xorg, pango, gtk2
|
||||||
, gnome2, mesa, nss, nspr, gtk_engines, freetype, dconf, libpng12, libxml2
|
, gnome2, mesa, nss, nspr, gtk_engines, freetype, dconf, libpng12, libxml2
|
||||||
, libjpeg, libredirect, tzdata, cacert, systemd, libcxxabi, libcxx, e2fsprogs, symlinkJoin
|
, libjpeg, libredirect, tzdata, cacert, systemd, libcxxabi, libcxx, e2fsprogs, symlinkJoin
|
||||||
, libpulseaudio, pcsclite, glib-networking
|
, libpulseaudio, pcsclite, glib-networking, llvmPackages_12
|
||||||
|
|
||||||
, homepage, version, prefix, hash
|
, homepage, version, prefix, hash
|
||||||
|
|
||||||
|
@ -99,7 +99,8 @@ stdenv.mkDerivation rec {
|
||||||
xorg.libXtst
|
xorg.libXtst
|
||||||
zlib
|
zlib
|
||||||
] ++ lib.optional (lib.versionOlder version "20.04") e2fsprogs
|
] ++ lib.optional (lib.versionOlder version "20.04") e2fsprogs
|
||||||
++ lib.optional (lib.versionAtLeast version "20.10") libpulseaudio;
|
++ lib.optional (lib.versionAtLeast version "20.10") libpulseaudio
|
||||||
|
++ lib.optional (lib.versionAtLeast version "21.12") llvmPackages_12.libunwind;
|
||||||
|
|
||||||
runtimeDependencies = [
|
runtimeDependencies = [
|
||||||
glib
|
glib
|
||||||
|
@ -120,10 +121,11 @@ stdenv.mkDerivation rec {
|
||||||
installPhase = let
|
installPhase = let
|
||||||
icaFlag = program:
|
icaFlag = program:
|
||||||
if (builtins.match "selfservice(.*)" program) != null then "--icaroot"
|
if (builtins.match "selfservice(.*)" program) != null then "--icaroot"
|
||||||
|
else if (lib.versionAtLeast version "21.12" && builtins.match "wfica(.*)" program != null) then null
|
||||||
else "-icaroot";
|
else "-icaroot";
|
||||||
wrap = program: ''
|
wrap = program: ''
|
||||||
wrapProgram $out/opt/citrix-icaclient/${program} \
|
wrapProgram $out/opt/citrix-icaclient/${program} \
|
||||||
--add-flags "${icaFlag program} $ICAInstDir" \
|
${lib.optionalString (icaFlag program != null) ''--add-flags "${icaFlag program} $ICAInstDir"''} \
|
||||||
--set ICAROOT "$ICAInstDir" \
|
--set ICAROOT "$ICAInstDir" \
|
||||||
--prefix LD_LIBRARY_PATH : "$ICAInstDir:$ICAInstDir/lib" \
|
--prefix LD_LIBRARY_PATH : "$ICAInstDir:$ICAInstDir/lib" \
|
||||||
--set LD_PRELOAD "${libredirect}/lib/libredirect.so" \
|
--set LD_PRELOAD "${libredirect}/lib/libredirect.so" \
|
||||||
|
|
|
@ -122,6 +122,17 @@ let
|
||||||
x86suffix = "25";
|
x86suffix = "25";
|
||||||
homepage = "https://www.citrix.com/downloads/workspace-app/linux/workspace-app-for-linux-latest.html";
|
homepage = "https://www.citrix.com/downloads/workspace-app/linux/workspace-app-for-linux-latest.html";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"21.12.0" = {
|
||||||
|
major = "21";
|
||||||
|
minor = "12";
|
||||||
|
patch = "0";
|
||||||
|
x64hash = "de81deab648e1ebe0ddb12aa9591c8014d7fad4eba0db768f25eb156330bb34d";
|
||||||
|
x86hash = "3746cdbe26727f7f6fb85fbe5f3e6df0322d79bb66e3a70158b22cb4f6b6b292";
|
||||||
|
x64suffix = "18";
|
||||||
|
x86suffix = "18";
|
||||||
|
homepage = "https://www.citrix.com/downloads/workspace-app/linux/workspace-app-for-linux-latest.html";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Retain attribute-names for abandoned versions of Citrix workspace to
|
# Retain attribute-names for abandoned versions of Citrix workspace to
|
||||||
|
|
|
@ -19,8 +19,11 @@ python3Packages.buildPythonApplication rec {
|
||||||
propagatedBuildInputs = [ gtk3 gdk-pixbuf gobject-introspection ]
|
propagatedBuildInputs = [ gtk3 gdk-pixbuf gobject-introspection ]
|
||||||
++ (with python3Packages; [ pygobject3 ]);
|
++ (with python3Packages; [ pygobject3 ]);
|
||||||
|
|
||||||
|
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
mv $out/bin/nicotine $out/bin/nicotine-plus
|
ln -s $out/bin/nicotine $out/bin/nicotine-plus
|
||||||
|
test -e $out/share/applications/org.nicotine_plus.Nicotine.desktop && exit 1
|
||||||
|
install -D data/org.nicotine_plus.Nicotine.desktop -t $out/share/applications
|
||||||
'';
|
'';
|
||||||
|
|
||||||
preFixup = ''
|
preFixup = ''
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "unison";
|
pname = "unison";
|
||||||
version = "2.51.4";
|
version = "2.51.5";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "bcpierce00";
|
owner = "bcpierce00";
|
||||||
repo = "unison";
|
repo = "unison";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-jcfq4X+r98bQqbQ3gRqJyryLdt1Y/2CLawqqIiUaQOo=";
|
sha256 = "sha256-pi5uYwPpIy0lERmgATWQCO3EA3Pg5pnn7gxv49FaPug=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ makeWrapper ]
|
nativeBuildInputs = [ makeWrapper ]
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
{lib, stdenvNoCC, haskellPackages, fetchurl, writers}:
|
{lib, stdenvNoCC, haskellPackages, fetchurl, writers}:
|
||||||
|
|
||||||
|
let
|
||||||
|
hledger-lib = haskellPackages.hledger-lib_1_24_1;
|
||||||
|
in
|
||||||
|
|
||||||
stdenvNoCC.mkDerivation rec {
|
stdenvNoCC.mkDerivation rec {
|
||||||
pname = "hledger-check-fancyassertions";
|
pname = "hledger-check-fancyassertions";
|
||||||
version = "1.23";
|
inherit (hledger-lib) version;
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
|
name = "hledger-check-fancyassertion-${version}.hs";
|
||||||
url = "https://raw.githubusercontent.com/simonmichael/hledger/hledger-lib-${version}/bin/hledger-check-fancyassertions.hs";
|
url = "https://raw.githubusercontent.com/simonmichael/hledger/hledger-lib-${version}/bin/hledger-check-fancyassertions.hs";
|
||||||
sha256 = "08p2din1j7l4c29ipn68k8vvs3ys004iy8a3zf318lzby4h04h0n";
|
sha256 = "0naggvivc6szsc8haa52a6lm079ikz5qfva0ljnqx0f1zlkxv984";
|
||||||
};
|
};
|
||||||
|
|
||||||
dontUnpack = true;
|
dontUnpack = true;
|
||||||
|
@ -15,11 +20,13 @@ stdenvNoCC.mkDerivation rec {
|
||||||
executable = writers.writeHaskell
|
executable = writers.writeHaskell
|
||||||
"hledger-check-fancyassertions"
|
"hledger-check-fancyassertions"
|
||||||
{
|
{
|
||||||
libraries = with haskellPackages; [
|
libraries = [
|
||||||
base base-compat base-compat-batteries filepath hledger-lib_1_24
|
hledger-lib
|
||||||
|
] ++ (with haskellPackages; [
|
||||||
|
base base-compat base-compat-batteries filepath
|
||||||
megaparsec microlens optparse-applicative string-qq text time
|
megaparsec microlens optparse-applicative string-qq text time
|
||||||
transformers
|
transformers
|
||||||
];
|
]);
|
||||||
inherit (haskellPackages) ghc;
|
inherit (haskellPackages) ghc;
|
||||||
}
|
}
|
||||||
src;
|
src;
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
{ stdenv , lib , fetchurl , appimageTools , makeWrapper , electron_11 }:
|
{ stdenv , lib , fetchurl , appimageTools , makeWrapper , electron }:
|
||||||
|
|
||||||
let
|
|
||||||
electron = electron_11;
|
|
||||||
in
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "super-productivity";
|
pname = "super-productivity";
|
||||||
version = "7.6.0";
|
version = "7.9.1";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://github.com/johannesjo/super-productivity/releases/download/v${version}/superProductivity-${version}.AppImage";
|
url = "https://github.com/johannesjo/super-productivity/releases/download/v${version}/superProductivity-${version}.AppImage";
|
||||||
sha256 = "f02a451a44f48a8e85a0c1269625d89fb1e0b8a75b7e217d96352064e6464ae5";
|
sha256 = "sha256:0lxnl5ai23dwfsyrkpi9l1a0gl0qn6vp7hzmca77nyx974d6j8m4";
|
||||||
name = "${pname}-${version}.AppImage";
|
name = "${pname}-${version}.AppImage";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
, stdenv
|
, stdenv
|
||||||
, fetchurl
|
, fetchurl
|
||||||
, hamlib
|
, hamlib
|
||||||
, fltk14
|
, fltk13
|
||||||
, libjpeg
|
, libjpeg
|
||||||
, libpng
|
, libpng
|
||||||
, portaudio
|
, portaudio
|
||||||
|
@ -31,7 +31,7 @@ stdenv.mkDerivation rec {
|
||||||
libXinerama
|
libXinerama
|
||||||
gettext
|
gettext
|
||||||
hamlib
|
hamlib
|
||||||
fltk14
|
fltk13
|
||||||
libjpeg
|
libjpeg
|
||||||
libpng
|
libpng
|
||||||
portaudio
|
portaudio
|
||||||
|
@ -39,11 +39,16 @@ stdenv.mkDerivation rec {
|
||||||
libsamplerate
|
libsamplerate
|
||||||
] ++ lib.optionals (stdenv.isLinux) [ libpulseaudio alsa-lib udev ];
|
] ++ lib.optionals (stdenv.isLinux) [ libpulseaudio alsa-lib udev ];
|
||||||
|
|
||||||
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
description = "Digital modem program";
|
description = "Digital modem program";
|
||||||
homepage = "https://sourceforge.net/projects/fldigi/";
|
homepage = "https://sourceforge.net/projects/fldigi/";
|
||||||
license = licenses.gpl3Plus;
|
license = licenses.gpl3Plus;
|
||||||
maintainers = with maintainers; [ relrod ftrvxmtrx ];
|
maintainers = with maintainers; [ relrod ftrvxmtrx ];
|
||||||
platforms = platforms.unix;
|
platforms = platforms.unix;
|
||||||
|
# unable to execute command: posix_spawn failed: Argument list too long
|
||||||
|
# Builds fine on aarch64-darwin
|
||||||
|
broken = stdenv.system == "x86_64-darwin";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "flex-ncat";
|
pname = "flex-ncat";
|
||||||
version = "0.0-20210420.0";
|
version = "0.1-20211223.0";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "kc2g-flex-tools";
|
owner = "kc2g-flex-tools";
|
||||||
repo = "nCAT";
|
repo = "nCAT";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "0wrdmlp9rrr4n0g9pj0j20ddskllyr59dr3p5fm9z0avkncn3a0m";
|
hash = "sha256-l5IH6EtWqxMLqUfIYpaKgZE9Jq8q4+WgZIazQ2scyxg=";
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "0npzhvpyaxvfaivycnscvh45lp0ycdg9xrlfm8vhfr835yj2adiv";
|
vendorSha256 = "sha256-OzYlpC8DZQc3qo7mnl5jHlxaCNxMW+Z3VG535e+G/1o=";
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://github.com/kc2g-flex-tools/nCAT";
|
homepage = "https://github.com/kc2g-flex-tools/nCAT";
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{ lib, fetchFromGitHub, python3Packages
|
{ lib, fetchFromGitHub, python3Packages
|
||||||
, hackrf, rtl-sdr, airspy, limesuite, libiio
|
, hackrf, rtl-sdr, airspy, limesuite, libiio
|
||||||
|
, libbladeRF
|
||||||
, qt5
|
, qt5
|
||||||
, USRPSupport ? false, uhd }:
|
, USRPSupport ? false, uhd }:
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ python3Packages.buildPythonApplication rec {
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ qt5.wrapQtAppsHook ];
|
nativeBuildInputs = [ qt5.wrapQtAppsHook ];
|
||||||
buildInputs = [ hackrf rtl-sdr airspy limesuite libiio ]
|
buildInputs = [ hackrf rtl-sdr airspy limesuite libiio libbladeRF ]
|
||||||
++ lib.optional USRPSupport uhd;
|
++ lib.optional USRPSupport uhd;
|
||||||
|
|
||||||
propagatedBuildInputs = with python3Packages; [
|
propagatedBuildInputs = with python3Packages; [
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "wsjtx";
|
pname = "wsjtx";
|
||||||
version = "2.5.2";
|
version = "2.5.3";
|
||||||
|
|
||||||
# This is a "superbuild" tarball containing both wsjtx and a hamlib fork
|
# This is a "superbuild" tarball containing both wsjtx and a hamlib fork
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "http://physics.princeton.edu/pulsar/k1jt/wsjtx-${version}.tgz";
|
url = "http://physics.princeton.edu/pulsar/k1jt/wsjtx-${version}.tgz";
|
||||||
sha256 = "sha256-4KSJYhfUya8nH1KTsZ7JRgh0KnKdqrgSfofsjWaX7/M=";
|
sha256 = "sha256-Dd99JBPn1TgPF8Yvqk+AZX8ZUuQjYS0Tx3y5A3VZsHw=";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Hamlib builds with autotools, wsjtx builds with cmake
|
# Hamlib builds with autotools, wsjtx builds with cmake
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "minimap2";
|
pname = "minimap2";
|
||||||
version = "2.22";
|
version = "2.23";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
repo = pname;
|
repo = pname;
|
||||||
owner = "lh3";
|
owner = "lh3";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-jYXJr2T1enZfSABVV5Kmd5OBtWZtQ2D/2eAlW2WHtGU=";
|
sha256 = "sha256-oNVpSINcXO2eKzOCr/Fl8tSMguRxzmlDNu7hLZeopoQ=";
|
||||||
};
|
};
|
||||||
|
|
||||||
buildInputs = [ zlib ];
|
buildInputs = [ zlib ];
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
, swig
|
, swig
|
||||||
, python
|
, python
|
||||||
, wxPython
|
, wxPython
|
||||||
, opencascade
|
|
||||||
, opencascade-occt
|
, opencascade-occt
|
||||||
, libngspice
|
, libngspice
|
||||||
, valgrind
|
, valgrind
|
||||||
|
@ -44,22 +43,16 @@
|
||||||
, baseName
|
, baseName
|
||||||
, kicadSrc
|
, kicadSrc
|
||||||
, kicadVersion
|
, kicadVersion
|
||||||
, i18n
|
|
||||||
, withOCE
|
|
||||||
, withOCC
|
, withOCC
|
||||||
, withNgspice
|
, withNgspice
|
||||||
, withScripting
|
, withScripting
|
||||||
|
, withI18n
|
||||||
|
, withPCM
|
||||||
, debug
|
, debug
|
||||||
, sanitizeAddress
|
, sanitizeAddress
|
||||||
, sanitizeThreads
|
, sanitizeThreads
|
||||||
, withI18n
|
|
||||||
}:
|
}:
|
||||||
|
|
||||||
assert lib.asserts.assertMsg (!(withOCE && stdenv.isAarch64)) "OCE fails a test on Aarch64";
|
|
||||||
assert lib.asserts.assertMsg (!(withOCC && withOCE))
|
|
||||||
"Only one of OCC and OCE may be enabled";
|
|
||||||
assert lib.assertMsg (!(stable && (sanitizeAddress || sanitizeThreads)))
|
|
||||||
"Only kicad-unstable(-small) supports address/thread sanitation";
|
|
||||||
assert lib.assertMsg (!(sanitizeAddress && sanitizeThreads))
|
assert lib.assertMsg (!(sanitizeAddress && sanitizeThreads))
|
||||||
"'sanitizeAddress' and 'sanitizeThreads' are mutually exclusive, use one.";
|
"'sanitizeAddress' and 'sanitizeThreads' are mutually exclusive, use one.";
|
||||||
|
|
||||||
|
@ -75,6 +68,7 @@ stdenv.mkDerivation rec {
|
||||||
# tagged releases don't have "unknown"
|
# tagged releases don't have "unknown"
|
||||||
# kicad nightlies use git describe --dirty
|
# kicad nightlies use git describe --dirty
|
||||||
# nix removes .git, so its approximated here
|
# nix removes .git, so its approximated here
|
||||||
|
# "6.99.0" doesn't have "-unknown", yet; so leaving this in case it returns
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
substituteInPlace CMakeModules/KiCadVersion.cmake \
|
substituteInPlace CMakeModules/KiCadVersion.cmake \
|
||||||
--replace "unknown" "${builtins.substring 0 10 src.rev}" \
|
--replace "unknown" "${builtins.substring 0 10 src.rev}" \
|
||||||
|
@ -82,23 +76,14 @@ stdenv.mkDerivation rec {
|
||||||
|
|
||||||
makeFlags = optionals (debug) [ "CFLAGS+=-Og" "CFLAGS+=-ggdb" ];
|
makeFlags = optionals (debug) [ "CFLAGS+=-Og" "CFLAGS+=-ggdb" ];
|
||||||
|
|
||||||
cmakeFlags = optionals (stable && withScripting) [
|
cmakeFlags = optionals (withScripting) [
|
||||||
"-DKICAD_SCRIPTING=ON"
|
"-DKICAD_SCRIPTING_WXPYTHON=ON"
|
||||||
"-DKICAD_SCRIPTING_MODULES=ON"
|
|
||||||
"-DKICAD_SCRIPTING_PYTHON3=ON"
|
|
||||||
"-DKICAD_SCRIPTING_WXPYTHON_PHOENIX=ON"
|
|
||||||
]
|
]
|
||||||
++ optionals (!withScripting) [
|
++ optionals (!withScripting) [
|
||||||
"-DKICAD_SCRIPTING=OFF"
|
|
||||||
"-DKICAD_SCRIPTING_WXPYTHON=OFF"
|
"-DKICAD_SCRIPTING_WXPYTHON=OFF"
|
||||||
]
|
]
|
||||||
++ optional (withNgspice) "-DKICAD_SPICE=ON"
|
++ optional (!withNgspice) "-DKICAD_SPICE=OFF"
|
||||||
++ optional (!withOCE) "-DKICAD_USE_OCE=OFF"
|
|
||||||
++ optional (!withOCC) "-DKICAD_USE_OCC=OFF"
|
++ optional (!withOCC) "-DKICAD_USE_OCC=OFF"
|
||||||
++ optionals (withOCE) [
|
|
||||||
"-DKICAD_USE_OCE=ON"
|
|
||||||
"-DOCE_DIR=${opencascade}"
|
|
||||||
]
|
|
||||||
++ optionals (withOCC) [
|
++ optionals (withOCC) [
|
||||||
"-DKICAD_USE_OCC=ON"
|
"-DKICAD_USE_OCC=ON"
|
||||||
"-DOCC_INCLUDE_DIR=${opencascade-occt}/include/opencascade"
|
"-DOCC_INCLUDE_DIR=${opencascade-occt}/include/opencascade"
|
||||||
|
@ -108,11 +93,20 @@ stdenv.mkDerivation rec {
|
||||||
"-DKICAD_STDLIB_DEBUG=ON"
|
"-DKICAD_STDLIB_DEBUG=ON"
|
||||||
"-DKICAD_USE_VALGRIND=ON"
|
"-DKICAD_USE_VALGRIND=ON"
|
||||||
]
|
]
|
||||||
|
++ optionals (!doInstallCheck) [
|
||||||
|
"-DKICAD_BUILD_QA_TESTS=OFF"
|
||||||
|
]
|
||||||
++ optionals (sanitizeAddress) [
|
++ optionals (sanitizeAddress) [
|
||||||
"-DKICAD_SANITIZE_ADDRESS=ON"
|
"-DKICAD_SANITIZE_ADDRESS=ON"
|
||||||
]
|
]
|
||||||
++ optionals (sanitizeThreads) [
|
++ optionals (sanitizeThreads) [
|
||||||
"-DKICAD_SANITIZE_THREADS=ON"
|
"-DKICAD_SANITIZE_THREADS=ON"
|
||||||
|
]
|
||||||
|
++ optionals (withI18n) [
|
||||||
|
"-DKICAD_BUILD_I18N=ON"
|
||||||
|
]
|
||||||
|
++ optionals (!withPCM) [
|
||||||
|
"-DKICAD_PCM=OFF"
|
||||||
];
|
];
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
@ -154,34 +148,27 @@ stdenv.mkDerivation rec {
|
||||||
curl
|
curl
|
||||||
openssl
|
openssl
|
||||||
boost
|
boost
|
||||||
|
swig
|
||||||
|
python
|
||||||
]
|
]
|
||||||
# unstable requires swig and python
|
|
||||||
# wxPython still optional
|
|
||||||
++ optionals (withScripting || (!stable)) [ swig python ]
|
|
||||||
++ optional (withScripting) wxPython
|
++ optional (withScripting) wxPython
|
||||||
++ optional (withNgspice) libngspice
|
++ optional (withNgspice) libngspice
|
||||||
++ optional (withOCE) opencascade
|
|
||||||
++ optional (withOCC) opencascade-occt
|
++ optional (withOCC) opencascade-occt
|
||||||
++ optional (debug) valgrind
|
++ optional (debug) valgrind
|
||||||
;
|
;
|
||||||
|
|
||||||
# debug builds fail all but the python test
|
# debug builds fail all but the python test
|
||||||
# 5.1.x fails the eeschema test
|
#doInstallCheck = !debug;
|
||||||
doInstallCheck = !debug && !stable;
|
# temporarily disabled until upstream issue 9888 is resolved
|
||||||
|
doInstallCheck = false;
|
||||||
installCheckTarget = "test";
|
installCheckTarget = "test";
|
||||||
|
|
||||||
dontStrip = debug;
|
dontStrip = debug;
|
||||||
|
|
||||||
postInstall = optionalString (withI18n) ''
|
|
||||||
mkdir -p $out/share
|
|
||||||
lndir ${i18n}/share $out/share
|
|
||||||
'';
|
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
description = "Just the built source without the libraries";
|
description = "Just the built source without the libraries";
|
||||||
longDescription = ''
|
longDescription = ''
|
||||||
Just the build products, optionally with the i18n linked in
|
Just the build products, the libraries are passed via an env var in the wrapper, default.nix
|
||||||
the libraries are passed via an env var in the wrapper, default.nix
|
|
||||||
'';
|
'';
|
||||||
homepage = "https://www.kicad.org/";
|
homepage = "https://www.kicad.org/";
|
||||||
license = lib.licenses.agpl3;
|
license = lib.licenses.agpl3;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue