Merge dc18c6f81c into haskell-updates

This commit is contained in:
nixpkgs-ci[bot]
2025-03-20 00:18:39 +00:00
committed by GitHub
309 changed files with 12892 additions and 1213 deletions
+1
View File
@@ -108,6 +108,7 @@ A few markups for other kinds of literals are also available:
These literal kinds are used mostly in NixOS option documentation.
This syntax is taken from [MyST](https://myst-parser.readthedocs.io/en/latest/syntax/syntax.html#roles-an-in-line-extension-point). Though, the feature originates from [reStructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-manpage) with slightly different syntax.
They are handled by `myst_role` defined per renderer. <!-- reverse references in code -->
#### Admonitions
+1
View File
@@ -156,6 +156,7 @@ let
makeScope makeScopeWithSplicing makeScopeWithSplicing'
extendMkDerivation;
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
inherit (self.generators) mkLuaInline;
inherit (self.meta) addMetaAttrs dontDistribute setName updateName
appendToName mapDerivationAttrset setPrio lowPrio lowPrioSet hiPrio
hiPrioSet licensesSpdx getLicenseFromSpdxId getLicenseFromSpdxIdOr
+2 -2
View File
@@ -743,6 +743,8 @@ in rec {
"nil"
else if isInt v || isFloat v || isString v || isBool v then
toJSON v
else if isPath v || isDerivation v then
toJSON "${v}"
else if isList v then
(if v == [ ] then "{}" else
"{${introSpace}${concatItems (map (value: "${toLua innerArgs value}") v)}${outroSpace}}")
@@ -752,8 +754,6 @@ in rec {
"(${v.expr})"
else if v == { } then
"{}"
else if isDerivation v then
''"${toString v}"''
else
"{${introSpace}${concatItems (
mapAttrsToList (key: value: "[${toJSON key}] = ${toLua innerArgs value}") v
+5 -5
View File
@@ -140,11 +140,6 @@ lib.mapAttrs mkLicense ({
fullName = "Apache License 2.0";
};
asl20-llvm = {
spdxId = "Apache-2.0 WITH LLVM-exception";
fullName = "Apache License 2.0 with LLVM Exceptions";
};
bitstreamVera = {
spdxId = "Bitstream-Vera";
fullName = "Bitstream Vera Font License";
@@ -859,6 +854,11 @@ lib.mapAttrs mkLicense ({
url = "https://opensource.franz.com/preamble.html";
};
llvm-exception = {
spdxId = "LLVM-exception";
fullName = "LLVM Exception"; # LLVM exceptions to the Apache 2.0 License
};
lppl1 = {
spdxId = "LPPL-1.0";
fullName = "LaTeX Project Public License v1.0";
+9
View File
@@ -834,6 +834,15 @@ rec {
};
};
# A value produced by `lib.mkLuaInline`
luaInline = mkOptionType {
name = "luaInline";
description = "inline lua";
descriptionClass = "noun";
check = x: x._type or null == "lua-inline";
merge = mergeEqualOption;
};
uniq = unique { message = ""; };
unique = { message }: type: mkOptionType rec {
+75
View File
@@ -579,6 +579,17 @@
githubId = 50264672;
name = "Adam Freeth";
};
adamperkowski = {
name = "Adam Perkowski";
email = "adas1per@protonmail.com";
matrix = "@xx0a_q:matrix.org";
github = "adamperkowski";
githubId = 75480869;
keys = [
{ fingerprint = "00F6 1623 FB56 BC5B B709 4E63 4CE6 C117 2DF6 BE79"; }
{ fingerprint = "5A53 0832 DA91 20B0 CA57 DDB6 7CBD B58E CF1D 3478"; }
];
};
adamt = {
email = "mail@adamtulinius.dk";
github = "adamtulinius";
@@ -1185,6 +1196,18 @@
githubId = 30437811;
name = "Alex Andrews";
};
alikindsys = {
email = "alice@blocovermelho.org";
github = "alikindsys";
githubId = 36565196;
name = "Alikind System";
keys = [
{
fingerprint = "7D31 15DC D912 C15A 2781 F7BB 511C B44B C752 2A89";
}
];
};
alirezameskin = {
email = "alireza.meskin@gmail.com";
github = "alirezameskin";
@@ -9103,6 +9126,12 @@
githubId = 39066502;
name = "Guekka";
};
guelakais = {
email = "koroyeldiores@gmail.com";
github = "Guelakais";
githubId = 76840985;
name = "GueLaKais";
};
guibert = {
email = "david.guibert@gmail.com";
github = "dguibert";
@@ -9176,6 +9205,11 @@
github = "gytis-ivaskevicius";
githubId = 23264966;
};
GZGavinZhao = {
name = "Gavin Zhao";
github = "GZGavinZhao";
githubId = 74938940;
};
h3cth0r = {
name = "Hector Miranda";
email = "hector.miranda@tec.mx";
@@ -10514,6 +10548,12 @@
githubId = 94313;
name = "Xianyi Lin";
};
izelnakri = {
email = "contact@izelnakri.com";
github = "izelnakri";
githubId = 1190931;
name = "Izel Nakri";
};
izorkin = {
email = "Izorkin@gmail.com";
github = "Izorkin";
@@ -11415,6 +11455,13 @@
githubId = 22916782;
name = "Joan Massachs";
};
joaomoreira = {
matrix = "@joaomoreira:matrix.org";
github = "joaoymoreira";
githubId = 151087767;
name = "João Moreira";
keys = [ { fingerprint = "F457 0A3A 5F89 22F8 F572 E075 EF8B F2C8 C5F4 097D"; } ];
};
joaquintrinanes = {
email = "hi@joaquint.io";
github = "JoaquinTrinanes";
@@ -14202,6 +14249,17 @@
githubId = 7910815;
name = "Alex McGrath";
};
lykos153 = {
email = "silvio.ankermann@cloudandheat.com";
github = "Lykos153";
githubId = 6453662;
name = "Silvio Ankermann";
keys = [
{
fingerprint = "8D47 6294 7205 541C 62A4 9C88 F422 6CA3 971C 4E97";
}
];
};
lyn = {
name = "Lyn";
matrix = "@lynatic:catgirl.cloud";
@@ -21399,6 +21457,11 @@
githubId = 19472270;
name = "Sebastian";
};
sebaguardian = {
name = "Sebaguardian";
github = "Sebaguardian";
githubId = 68247013;
};
sebastianblunt = {
name = "Sebastian Blunt";
email = "nix@sebastianblunt.com";
@@ -21986,6 +22049,11 @@
githubId = 91412114;
keys = [ { fingerprint = "C1DA A551 B422 7A6F 3FD9 6B3A 467B 7D12 9EA7 3AC9"; } ];
};
silvanshade = {
github = "silvanshade";
githubId = 11022302;
name = "silvanshade";
};
Silver-Golden = {
name = "Brendan Golden";
email = "github+nixpkgs@brendan.ie";
@@ -22510,6 +22578,13 @@
githubId = 47164123;
name = "Spoonbaker";
};
sportshead = {
email = "me@sportshead.dev";
github = "sportshead";
githubId = 32637656;
name = "sportshead";
keys = [ { fingerprint = "A6B6 D031 782E BDF7 631A 8E7E A874 DB2C BFD3 CFD0"; } ];
};
sprock = {
email = "rmason@mun.ca";
github = "sprock";
+2 -1
View File
@@ -1018,8 +1018,9 @@ with lib.maintainers;
rocm = {
members = [
Madouura
Flakebi
GZGavinZhao
LunNova
mschwaig
];
githubTeams = [ "rocm-maintainers" ];
@@ -232,6 +232,13 @@ merging is handled.
definitions cannot be merged. The regular expression is processed
using `builtins.match`.
### Specialised types {#sec-option-types-specialised}
`types.luaInline`
: A string wrapped using `lib.mkLuaInline`. Allows embedding lua expressions
inline within generated lua. Multiple definitions cannot be merged.
## Submodule types {#sec-option-types-submodule}
Submodules are detailed in [Submodule](#section-option-types-submodule).
@@ -402,6 +402,31 @@ have a predefined type and string generator already declared under
: Outputs the given attribute set as an Elixir map, instead of the
default Elixir keyword list
`pkgs.formats.lua { asBindings ? false, multiline ? true, columnWidth ? 100, indentWidth ? 2, indentUsingTabs ? false }`
: A function taking an attribute set with values
`asBindings` (default `false`)
: Whether to treat attributes as variable bindings
`multiline` (default `true`)
: Whether to procude a multiline output. The output may still wrap across
multiple lines if it would otherwise exceed `columnWidth`.
`columnWidth` (default `100`)
: The column width to use to attempt to wrap lines.
`indentWidth` (default `2`)
: The width of a single indentation level.
`indentUsingTabs` (default `false`)
: Whether the indentation should use tabs instead of spaces.
`pkgs.formats.php { finalVariable }` []{#pkgs-formats-php}
: A function taking an attribute set with values
+3
View File
@@ -1592,6 +1592,9 @@
"sec-option-types-string": [
"index.html#sec-option-types-string"
],
"sec-option-types-specialised": [
"index.html#sec-option-types-specialised"
],
"sec-option-types-submodule": [
"index.html#sec-option-types-submodule"
],
@@ -111,6 +111,8 @@
- [Schroot](https://codeberg.org/shelter/reschroot), a lightweight virtualisation tool. Securely enter a chroot and run a command or login shell. Available as [programs.schroot](#opt-programs.schroot.enable).
- [Firezone](https://firezone.dev), an enterprise-ready zero-trust access platform built on WireGuard. This includes the server stack as [services.firezone.server.enable](#opt-services.firezone.server.enable), a TURN/STUN relay service as [services.firezone.relay.enable](#opt-services.firezone.relay.enable), a gateway service as [services.firezone.gateway.enable](#opt-services.firezone.gateway.enable), a headless client as [services.firezone.headless-client.enable](#opt-services.firezone.headless-client.enable) and a GUI client as [services.firezone.gui-client.enable](#opt-services.firezone.gui-client.enable).
- [crab-hole](https://github.com/LuckyTurtleDev/crab-hole), a cross platform Pi-hole clone written in Rust using hickory-dns/trust-dns. Available as [services.crab-hole](#opt-services.crab-hole.enable).
- [zwave-js-ui](https://zwave-js.github.io/zwave-js-ui/), a full featured Z-Wave Control Panel and MQTT Gateway. Available as [services.zwave-js-ui](#opt-services.zwave-js-ui.enable).
+1 -1
View File
@@ -376,4 +376,4 @@ foreach my $u (values %usersOut) {
updateFile("/etc/subuid", join("\n", @subUids) . "\n");
updateFile("/etc/subgid", join("\n", @subGids) . "\n");
updateFile($subUidMapFile, encode_json($subUidMap) . "\n");
updateFile($subUidMapFile, to_json($subUidMap) . "\n");
+15
View File
@@ -951,6 +951,21 @@ in {
}
] ++ flatten (flip mapAttrsToList cfg.users (name: user:
[
(
let
# Things fail in various ways with especially non-ascii usernames.
# This regex mirrors the one from shadow's is_valid_name:
# https://github.com/shadow-maint/shadow/blob/bee77ffc291dfed2a133496db465eaa55e2b0fec/lib/chkname.c#L68
# though without the trailing $, because Samba 3 got its last release
# over 10 years ago and is not in Nixpkgs anymore,
# while later versions don't appear to require anything like that.
nameRegex = "[a-zA-Z0-9_.][a-zA-Z0-9_.-]*";
in
{
assertion = builtins.match nameRegex user.name != null;
message = "The username \"${user.name}\" is not valid, it does not match the regex \"${nameRegex}\".";
}
)
{
assertion = (user.hashedPassword != null)
-> (match ".*:.*" user.hashedPassword == null);
+4 -1
View File
@@ -47,7 +47,10 @@ let
let
module = ../. + "/installer/sd-card/sd-image-${pkgs.targetPlatform.qemuArch}.nix";
in
if builtins.pathExists module then [ module ] else throw "The module ${module} does not exist.";
if builtins.pathExists module then
[ module ]
else
throw "The module ${toString module} does not exist.";
};
kexec = ../installer/netboot/netboot-minimal.nix;
};
+6
View File
@@ -1101,6 +1101,11 @@
./services/networking/firewall.nix
./services/networking/firewall-iptables.nix
./services/networking/firewall-nftables.nix
./services/networking/firezone/gateway.nix
./services/networking/firezone/gui-client.nix
./services/networking/firezone/headless-client.nix
./services/networking/firezone/relay.nix
./services/networking/firezone/server.nix
./services/networking/flannel.nix
./services/networking/freenet.nix
./services/networking/freeradius.nix
@@ -1364,6 +1369,7 @@
./services/scheduling/atd.nix
./services/scheduling/cron.nix
./services/scheduling/fcron.nix
./services/scheduling/prefect.nix
./services/scheduling/scx.nix
./services/search/elasticsearch-curator.nix
./services/search/elasticsearch.nix
@@ -9,7 +9,8 @@ let
registrationFile = "${dataDir}/telegram-registration.yaml";
cfg = config.services.mautrix-telegram;
settingsFormat = pkgs.formats.json { };
settingsFile = settingsFormat.generate "mautrix-telegram-config.json" cfg.settings;
settingsFileUnsubstituted = settingsFormat.generate "mautrix-telegram-config.json" cfg.settings;
settingsFile = "${dataDir}/config.json";
in
{
@@ -132,10 +133,37 @@ in
List of Systemd services to require and wait for when starting the application service.
'';
};
registerToSynapse = lib.mkOption {
type = lib.types.bool;
default = config.services.matrix-synapse.enable;
defaultText = lib.literalExpression "config.services.matrix-synapse.enable";
description = ''
Whether to add the bridge's app service registration file to
`services.matrix-synapse.settings.app_service_config_files`.
'';
};
};
};
config = lib.mkIf cfg.enable {
users.users.mautrix-telegram = {
isSystemUser = true;
group = "mautrix-telegram";
home = dataDir;
description = "Mautrix-Telegram bridge user";
};
users.groups.mautrix-telegram = { };
services.matrix-synapse = lib.mkIf cfg.registerToSynapse {
settings.app_service_config_files = [ registrationFile ];
};
systemd.services.matrix-synapse = lib.mkIf cfg.registerToSynapse {
serviceConfig.SupplementaryGroups = [ "mautrix-telegram" ];
};
systemd.services.mautrix-telegram = {
description = "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge.";
@@ -161,6 +189,16 @@ in
preStart =
''
# substitute the settings file by environment variables
# in this case read from EnvironmentFile
test -f '${settingsFile}' && rm -f '${settingsFile}'
old_umask=$(umask)
umask 0177
${pkgs.envsubst}/bin/envsubst \
-o '${settingsFile}' \
-i '${settingsFileUnsubstituted}'
umask $old_umask
# generate the appservice's registration file if absent
if [ ! -f '${registrationFile}' ]; then
${pkgs.mautrix-telegram}/bin/mautrix-telegram \
@@ -168,6 +206,19 @@ in
--config='${settingsFile}' \
--registration='${registrationFile}'
fi
old_umask=$(umask)
umask 0177
# 1. Overwrite registration tokens in config
# is set, set it as the login shared secret value for the configured
# homeserver domain.
${pkgs.yq}/bin/yq -s '.[0].appservice.as_token = .[1].as_token
| .[0].appservice.hs_token = .[1].hs_token
| .[0]' \
'${settingsFile}' '${registrationFile}' > '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
umask $old_umask
''
+ lib.optionalString (pkgs.mautrix-telegram ? alembic) ''
# run automatic database init and migration scripts
@@ -175,6 +226,8 @@ in
'';
serviceConfig = {
User = "mautrix-telegram";
Group = "mautrix-telegram";
Type = "simple";
Restart = "always";
@@ -184,7 +237,6 @@ in
ProtectKernelModules = true;
ProtectControlGroups = true;
DynamicUser = true;
PrivateTmp = true;
WorkingDirectory = pkgs.mautrix-telegram; # necessary for the database migration scripts to be found
StateDirectory = baseNameOf dataDir;
@@ -0,0 +1,159 @@
{
lib,
pkgs,
config,
...
}:
let
inherit (lib)
boolToString
getExe
mkEnableOption
mkIf
mkOption
mkPackageOption
types
;
cfg = config.services.firezone.gateway;
in
{
options = {
services.firezone.gateway = {
enable = mkOption {
default = false;
example = true;
description = ''
Whether to enable the firezone gateway.
You have to manually masquerade and forward traffic from the
tun-firezone interface to your resource! Refer to the
[upstream setup script](https://github.com/firezone/firezone/blob/8c7c0a9e8e33ae790aeb75fdb5a15432c2870b79/scripts/gateway-systemd-install.sh#L154-L168)
for a list of iptable commands.
See the firezone nixos test in this repository for an nftables based example.
'';
type = lib.types.bool;
};
package = mkPackageOption pkgs "firezone-gateway" { };
name = mkOption {
type = types.str;
description = "The name of this gateway as shown in firezone";
};
apiUrl = mkOption {
type = types.strMatching "^wss://.+/$";
example = "wss://firezone.example.com/api/";
description = ''
The URL of your firezone server's API. This should be the same
as your server's setting for {option}`services.firezone.server.settings.api.externalUrl`,
but with `wss://` instead of `https://`.
'';
};
tokenFile = mkOption {
type = types.path;
example = "/run/secrets/firezone-gateway-token";
description = ''
A file containing the firezone gateway token. Do not use a nix-store path here
as it will make the token publicly readable!
This file will be passed via systemd credentials, it should only be accessible
by the root user.
'';
};
logLevel = mkOption {
type = types.str;
default = "info";
description = ''
The log level for the firezone application. See
[RUST_LOG](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)
for the format.
'';
};
enableTelemetry = mkEnableOption "telemetry";
};
};
config = mkIf cfg.enable {
systemd.services.firezone-gateway = {
description = "Gateway service for the Firezone zero-trust access platform";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.util-linux ];
script = ''
# If FIREZONE_ID is not given by the user, use a persisted (or newly generated) uuid.
if [[ -z "''${FIREZONE_ID:-}" ]]; then
if [[ ! -e gateway_id ]]; then
uuidgen -r > gateway_id
fi
export FIREZONE_ID=$(< gateway_id)
fi
export FIREZONE_TOKEN=$(< "$CREDENTIALS_DIRECTORY/firezone-token")
exec ${getExe cfg.package}
'';
environment = {
FIREZONE_API_URL = cfg.apiUrl;
FIREZONE_NAME = cfg.name;
FIREZONE_NO_TELEMETRY = boolToString (!cfg.enableTelemetry);
RUST_LOG = cfg.logLevel;
};
serviceConfig = {
Type = "exec";
DynamicUser = true;
User = "firezone-gateway";
LoadCredential = [ "firezone-token:${cfg.tokenFile}" ];
DeviceAllow = "/dev/net/tun";
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
StateDirectory = "firezone-gateway";
WorkingDirectory = "/var/lib/firezone-gateway";
Restart = "on-failure";
RestartSec = 10;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = "@system-service";
UMask = "077";
};
};
};
meta.maintainers = with lib.maintainers; [
oddlama
patrickdag
];
}
@@ -0,0 +1,138 @@
{
lib,
pkgs,
config,
...
}:
let
inherit (lib)
boolToString
getExe'
mkEnableOption
mkIf
mkOption
mkPackageOption
types
;
cfg = config.services.firezone.gui-client;
in
{
options = {
services.firezone.gui-client = {
enable = mkEnableOption "the firezone gui client";
package = mkPackageOption pkgs "firezone-gui-client" { };
allowedUsers = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
All listed users will become part of the `firezone-client` group so
they can control the IPC service. This is a convenience option.
'';
};
name = mkOption {
type = types.str;
description = "The name of this client as shown in firezone";
};
logLevel = mkOption {
type = types.str;
default = "info";
description = ''
The log level for the firezone application. See
[RUST_LOG](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)
for the format.
'';
};
};
};
config = mkIf cfg.enable {
users.groups.firezone-client.members = cfg.allowedUsers;
# Required for deep-link mimetype registration
environment.systemPackages = [ cfg.package ];
# Required for the token store in the gui application
services.gnome.gnome-keyring.enable = true;
systemd.services.firezone-ipc-service = {
description = "GUI IPC service for the Firezone zero-trust access platform";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.util-linux ];
script = ''
# If FIREZONE_ID is not given by the user, use a persisted (or newly generated) uuid.
if [[ -z "''${FIREZONE_ID:-}" ]]; then
if [[ ! -e client_id ]]; then
uuidgen -r > client_id
fi
export FIREZONE_ID=$(< client_id)
fi
exec ${getExe' cfg.package "firezone-client-ipc"} run
'';
environment = {
FIREZONE_NAME = cfg.name;
LOG_DIR = "%L/dev.firezone.client";
RUST_LOG = cfg.logLevel;
};
serviceConfig = {
Type = "notify";
DeviceAllow = "/dev/net/tun";
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
# This block contains hardcoded values in the client, we cannot change these :(
Group = "firezone-client";
RuntimeDirectory = "dev.firezone.client";
StateDirectory = "dev.firezone.client";
WorkingDirectory = "/var/lib/dev.firezone.client";
LogsDirectory = "dev.firezone.client";
Restart = "on-failure";
RestartSec = 10;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = "@system-service";
UMask = "077";
};
};
};
meta.maintainers = with lib.maintainers; [
oddlama
patrickdag
];
}
@@ -0,0 +1,148 @@
{
lib,
pkgs,
config,
...
}:
let
inherit (lib)
boolToString
getExe
mkEnableOption
mkIf
mkOption
mkPackageOption
types
;
cfg = config.services.firezone.headless-client;
in
{
options = {
services.firezone.headless-client = {
enable = mkEnableOption "the firezone headless client";
package = mkPackageOption pkgs "firezone-headless-client" { };
name = mkOption {
type = types.str;
description = "The name of this client as shown in firezone";
};
apiUrl = mkOption {
type = types.strMatching "^wss://.+/$";
example = "wss://firezone.example.com/api/";
description = ''
The URL of your firezone server's API. This should be the same
as your server's setting for {option}`services.firezone.server.settings.api.externalUrl`,
but with `wss://` instead of `https://`.
'';
};
tokenFile = mkOption {
type = types.path;
example = "/run/secrets/firezone-client-token";
description = ''
A file containing the firezone client token. Do not use a nix-store path here
as it will make the token publicly readable!
This file will be passed via systemd credentials, it should only be accessible
by the root user.
'';
};
logLevel = mkOption {
type = types.str;
default = "info";
description = ''
The log level for the firezone application. See
[RUST_LOG](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)
for the format.
'';
};
enableTelemetry = mkEnableOption "telemetry";
};
};
config = mkIf cfg.enable {
systemd.services.firezone-headless-client = {
description = "headless client service for the Firezone zero-trust access platform";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.util-linux ];
script = ''
# If FIREZONE_ID is not given by the user, use a persisted (or newly generated) uuid.
if [[ -z "''${FIREZONE_ID:-}" ]]; then
if [[ ! -e client_id ]]; then
uuidgen -r > client_id
fi
export FIREZONE_ID=$(< client_id)
fi
exec ${getExe cfg.package}
'';
environment = {
FIREZONE_API_URL = cfg.apiUrl;
FIREZONE_NAME = cfg.name;
FIREZONE_NO_TELEMETRY = boolToString (!cfg.enableTelemetry);
FIREZONE_TOKEN_PATH = "%d/firezone-token";
LOG_DIR = "%L/dev.firezone.client";
RUST_LOG = cfg.logLevel;
};
serviceConfig = {
Type = "exec";
LoadCredential = [ "firezone-token:${cfg.tokenFile}" ];
DeviceAllow = "/dev/net/tun";
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
# Hardcoded values in the client :(
RuntimeDirectory = "dev.firezone.client";
StateDirectory = "dev.firezone.client";
WorkingDirectory = "/var/lib/dev.firezone.client";
LogsDirectory = "dev.firezone.client";
Restart = "on-failure";
RestartSec = 10;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = "@system-service";
UMask = "077";
};
};
};
meta.maintainers = with lib.maintainers; [
oddlama
patrickdag
];
}
@@ -0,0 +1,709 @@
defmodule Provision do
alias Domain.{Repo, Accounts, Auth, Actors, Resources, Tokens, Gateways, Relays, Policies}
require Logger
# UUID Mapping handling
defmodule UuidMapping do
@mapping_file "provision-uuids.json"
# Loads the mapping from file
def load do
mappings = case File.read(@mapping_file) do
{:ok, content} ->
case Jason.decode(content) do
{:ok, mapping} -> mapping
_ -> %{"accounts" => %{}}
end
_ -> %{"accounts" => %{}}
end
Process.put(:uuid_mappings, mappings)
mappings
end
# Saves the current mapping (defaulting to the one in the process dictionary)
def save(mapping \\ Process.get(:uuid_mappings)) do
File.write!(@mapping_file, Jason.encode!(mapping))
end
# Retrieves the account-level mapping from a given mapping (or from Process)
def get_account(mapping \\ Process.get(:uuid_mappings), account_slug) do
get_in(mapping, ["accounts", account_slug]) || %{}
end
# Retrieves the entity mapping for a specific account and type
def get_entities(mapping \\ Process.get(:uuid_mappings), account_slug, type) do
get_in(mapping, ["accounts", account_slug, type]) || %{}
end
# Retrieves an entity mapping for a specific account, type and external_id
def get_entity(mapping \\ Process.get(:uuid_mappings), account_slug, type, external_id) do
get_in(mapping, ["accounts", account_slug, type, external_id])
end
# Updates (or creates) the account UUID mapping and stores it in the process dictionary.
def update_account(account_slug, uuid) do
mapping = Process.get(:uuid_mappings) || load()
mapping = ensure_account_exists(mapping, account_slug)
mapping = put_in(mapping, ["accounts", account_slug, "id"], uuid)
Process.put(:uuid_mappings, mapping)
mapping
end
# Ensures that the given account exists in the mapping.
def ensure_account_exists(mapping, account_slug) do
if not Map.has_key?(mapping["accounts"], account_slug) do
put_in(mapping, ["accounts", account_slug], %{})
else
mapping
end
end
# Updates (or creates) the mapping for entities of a given type for the account.
def update_entities(account_slug, type, new_entries) do
mapping = Process.get(:uuid_mappings) || load()
mapping = ensure_account_exists(mapping, account_slug)
current = get_entities(mapping, account_slug, type)
mapping = put_in(mapping, ["accounts", account_slug, type], Map.merge(current, new_entries))
Process.put(:uuid_mappings, mapping)
mapping
end
# Removes an entire account from the mapping.
def remove_account(account_slug) do
mapping = Process.get(:uuid_mappings) || load()
mapping = update_in(mapping, ["accounts"], fn accounts ->
Map.delete(accounts, account_slug)
end)
Process.put(:uuid_mappings, mapping)
mapping
end
# Removes a specific entity mapping for the account.
def remove_entity(account_slug, type, key) do
mapping = Process.get(:uuid_mappings) || load()
mapping = update_in(mapping, ["accounts", account_slug, type], fn entities ->
Map.delete(entities || %{}, key)
end)
Process.put(:uuid_mappings, mapping)
mapping
end
end
defp resolve_references(value) when is_map(value) do
Enum.into(value, %{}, fn {k, v} -> {k, resolve_references(v)} end)
end
defp resolve_references(value) when is_list(value) do
Enum.map(value, &resolve_references/1)
end
defp resolve_references(value) when is_binary(value) do
Regex.replace(~r/\{env:([^}]+)\}/, value, fn _, var ->
System.get_env(var) || raise "Environment variable #{var} not set"
end)
end
defp resolve_references(value), do: value
defp atomize_keys(map) when is_map(map) do
Enum.into(map, %{}, fn {k, v} ->
{
if(is_binary(k), do: String.to_atom(k), else: k),
if(is_map(v), do: atomize_keys(v), else: v)
}
end)
end
defp cleanup_account(uuid) do
case Accounts.fetch_account_by_id_or_slug(uuid) do
{:ok, value} when value.deleted_at == nil ->
Logger.info("Deleting removed account #{value.slug}")
value |> Ecto.Changeset.change(%{ deleted_at: DateTime.utc_now() }) |> Repo.update!()
_ -> :ok
end
end
defp cleanup_actor(uuid, subject) do
case Actors.fetch_actor_by_id(uuid, subject) do
{:ok, value} ->
Logger.info("Deleting removed actor #{value.name}")
{:ok, _} = Actors.delete_actor(value, subject)
_ -> :ok
end
end
defp cleanup_provider(uuid, subject) do
case Auth.fetch_provider_by_id(uuid, subject) do
{:ok, value} ->
Logger.info("Deleting removed provider #{value.name}")
{:ok, _} = Auth.delete_provider(value, subject)
_ -> :ok
end
end
defp cleanup_gateway_group(uuid, subject) do
case Gateways.fetch_group_by_id(uuid, subject) do
{:ok, value} ->
Logger.info("Deleting removed gateway group #{value.name}")
{:ok, _} = Gateways.delete_group(value, subject)
_ -> :ok
end
end
defp cleanup_relay_group(uuid, subject) do
case Relays.fetch_group_by_id(uuid, subject) do
{:ok, value} ->
Logger.info("Deleting removed relay group #{value.name}")
{:ok, _} = Relays.delete_group(value, subject)
_ -> :ok
end
end
defp cleanup_actor_group(uuid, subject) do
case Actors.fetch_group_by_id(uuid, subject) do
{:ok, value} ->
Logger.info("Deleting removed actor group #{value.name}")
{:ok, _} = Actors.delete_group(value, subject)
_ -> :ok
end
end
# Fetch resource by uuid, but follow the chain of replacements if any
defp fetch_resource(uuid, subject) do
case Resources.fetch_resource_by_id(uuid, subject) do
{:ok, resource} when resource.replaced_by_resource_id != nil -> fetch_resource(resource.replaced_by_resource_id, subject)
v -> v
end
end
defp cleanup_resource(uuid, subject) do
case fetch_resource(uuid, subject) do
{:ok, value} when value.deleted_at == nil ->
Logger.info("Deleting removed resource #{value.name}")
{:ok, _} = Resources.delete_resource(value, subject)
_ -> :ok
end
end
# Fetch policy by uuid, but follow the chain of replacements if any
defp fetch_policy(uuid, subject) do
case Policies.fetch_policy_by_id(uuid, subject) do
{:ok, policy} when policy.replaced_by_policy_id != nil -> fetch_policy(policy.replaced_by_policy_id, subject)
v -> v
end
end
defp cleanup_policy(uuid, subject) do
case fetch_policy(uuid, subject) do
{:ok, value} when value.deleted_at == nil ->
Logger.info("Deleting removed policy #{value.description}")
{:ok, _} = Policies.delete_policy(value, subject)
_ -> :ok
end
end
defp cleanup_entity_type(account_slug, entity_type, cleanup_fn, temp_admin_subject) do
# Get mapping for this entity type
existing_entities = UuidMapping.get_entities(account_slug, entity_type)
# Get current entities from account data
current_entities = Process.get(:current_entities)
# Determine which ones to remove
removed_entity_ids = Map.keys(existing_entities) -- (current_entities[entity_type] || [])
# Process each entity to remove
Enum.each(removed_entity_ids, fn entity_id ->
case existing_entities[entity_id] do
nil -> :ok
uuid ->
cleanup_fn.(uuid, temp_admin_subject)
UuidMapping.remove_entity(account_slug, entity_type, entity_id)
end
end)
end
defp collect_current_entities(account_data) do
%{
"actors" => Map.keys(account_data["actors"] || %{}),
"providers" => Map.keys(account_data["auth"] || %{}),
"gateway_groups" => Map.keys(account_data["gatewayGroups"] || %{}),
"relay_groups" => Map.keys(account_data["relayGroups"] || %{}),
"actor_groups" => Map.keys(account_data["groups"] || %{}) ++ ["everyone"],
"resources" => Map.keys(account_data["resources"] || %{}),
"policies" => Map.keys(account_data["policies"] || %{})
}
end
defp nil_if_deleted_or_not_found(value) do
case value do
nil -> nil
{:error, :not_found} -> nil
{:ok, value} when value.deleted_at != nil -> nil
v -> v
end
end
defp create_temp_admin(account, email_provider) do
temp_admin_actor_email = "firezone-provision@localhost.local"
temp_admin_actor_context = %Auth.Context{
type: :browser,
user_agent: "Unspecified/0.0",
remote_ip: {127, 0, 0, 1},
remote_ip_location_region: "N/A",
remote_ip_location_city: "N/A",
remote_ip_location_lat: 0.0,
remote_ip_location_lon: 0.0
}
{:ok, temp_admin_actor} =
Actors.create_actor(account, %{
type: :account_admin_user,
name: "Provisioning"
})
{:ok, temp_admin_actor_email_identity} =
Auth.create_identity(temp_admin_actor, email_provider, %{
provider_identifier: temp_admin_actor_email,
provider_identifier_confirmation: temp_admin_actor_email
})
{:ok, temp_admin_actor_token} =
Auth.create_token(temp_admin_actor_email_identity, temp_admin_actor_context, "temporarynonce", DateTime.utc_now() |> DateTime.add(1, :hour))
{:ok, temp_admin_subject} =
Auth.build_subject(temp_admin_actor_token, temp_admin_actor_context)
{temp_admin_subject, temp_admin_actor, temp_admin_actor_email_identity, temp_admin_actor_token}
end
defp cleanup_temp_admin(temp_admin_actor, temp_admin_actor_email_identity, temp_admin_actor_token, subject) do
Logger.info("Cleaning up temporary admin actor")
{:ok, _} = Tokens.delete_token(temp_admin_actor_token, subject)
{:ok, _} = Auth.delete_identity(temp_admin_actor_email_identity, subject)
{:ok, _} = Actors.delete_actor(temp_admin_actor, subject)
end
def provision() do
Logger.info("Starting provisioning")
# Load desired state
json_file = "provision-state.json"
{:ok, raw_json} = File.read(json_file)
{:ok, %{"accounts" => accounts}} = Jason.decode(raw_json)
accounts = resolve_references(accounts)
# Load existing UUID mappings into the process dictionary.
UuidMapping.load()
# Clean up removed accounts first
current_account_slugs = Map.keys(accounts)
existing_accounts = Map.keys(Process.get(:uuid_mappings)["accounts"])
removed_accounts = existing_accounts -- current_account_slugs
Enum.each(removed_accounts, fn slug ->
if uuid = get_in(Process.get(:uuid_mappings), ["accounts", slug, "id"]) do
cleanup_account(uuid)
# Remove the account from the UUID mapping.
UuidMapping.remove_account(slug)
end
end)
multi = Enum.reduce(accounts, Ecto.Multi.new(), fn {slug, account_data}, multi ->
account_attrs = atomize_keys(%{
name: account_data["name"],
slug: slug,
features: Map.get(account_data, "features", %{}),
metadata: Map.get(account_data, "metadata", %{}),
limits: Map.get(account_data, "limits", %{})
})
multi = multi
|> Ecto.Multi.run({:account, slug}, fn repo, _changes ->
case Accounts.fetch_account_by_id_or_slug(slug) do
{:ok, acc} ->
Logger.info("Updating existing account #{slug}")
updated_acc = acc |> Ecto.Changeset.change(account_attrs) |> repo.update!()
{:ok, {:existing, updated_acc}}
_ ->
Logger.info("Creating new account #{slug}")
{:ok, account} = Accounts.create_account(account_attrs)
Logger.info("Creating internet gateway group")
{:ok, internet_site} = Gateways.create_internet_group(account)
Logger.info("Creating internet resource")
{:ok, _internet_resource} = Resources.create_internet_resource(account, internet_site)
# Store mapping of slug to UUID
UuidMapping.update_account(slug, account.id)
{:ok, {:new, account}}
end
end)
|> Ecto.Multi.run({:everyone_group, slug}, fn _repo, changes ->
case Map.get(changes, {:account, slug}) do
{:new, account} ->
Logger.info("Creating everyone group for new account")
{:ok, actor_group} = Actors.create_managed_group(account, %{name: "Everyone", membership_rules: [%{operator: true}]})
UuidMapping.update_entities(slug, "actor_groups", %{"everyone" => actor_group.id})
{:ok, actor_group}
{:existing, _account} ->
{:ok, :skipped}
end
end)
|> Ecto.Multi.run({:email_provider, slug}, fn _repo, changes ->
case Map.get(changes, {:account, slug}) do
{:new, account} ->
Logger.info("Creating default email provider for new account")
Auth.create_provider(account, %{name: "Email", adapter: :email, adapter_config: %{}})
{:existing, account} ->
Auth.Provider.Query.not_disabled()
|> Auth.Provider.Query.by_adapter(:email)
|> Auth.Provider.Query.by_account_id(account.id)
|> Repo.fetch(Auth.Provider.Query, [])
end
end)
|> Ecto.Multi.run({:temp_admin, slug}, fn _repo, changes ->
{_, account} = changes[{:account, slug}]
email_provider = changes[{:email_provider, slug}]
{:ok, create_temp_admin(account, email_provider)}
end)
# Clean up removed entities for this account after we have an admin subject
multi = multi
|> Ecto.Multi.run({:cleanup_entities, slug}, fn _repo, changes ->
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
# Store current entities in process dictionary for our helper function
current_entities = collect_current_entities(account_data)
Process.put(:current_entities, current_entities)
# Define entity types and their cleanup functions
entity_types = [
{"actors", &cleanup_actor/2},
{"providers", &cleanup_provider/2},
{"gateway_groups", &cleanup_gateway_group/2},
{"relay_groups", &cleanup_relay_group/2},
{"actor_groups", &cleanup_actor_group/2},
{"resources", &cleanup_resource/2},
{"policies", &cleanup_policy/2}
]
# Clean up each entity type
Enum.each(entity_types, fn {entity_type, cleanup_fn} ->
cleanup_entity_type(slug, entity_type, cleanup_fn, temp_admin_subject)
end)
{:ok, :cleaned}
end)
# Create or update actors
multi = Enum.reduce(account_data["actors"] || %{}, multi, fn {external_id, actor_data}, multi ->
actor_attrs = atomize_keys(%{
name: actor_data["name"],
type: String.to_atom(actor_data["type"])
})
Ecto.Multi.run(multi, {:actor, slug, external_id}, fn _repo, changes ->
{_, account} = changes[{:account, slug}]
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
uuid = UuidMapping.get_entity(slug, "actors", external_id)
case uuid && Actors.fetch_actor_by_id(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
nil ->
Logger.info("Creating new actor #{actor_data["name"]}")
{:ok, actor} = Actors.create_actor(account, actor_attrs)
# Update the mapping without manually handling Process.get/put.
UuidMapping.update_entities(slug, "actors", %{external_id => actor.id})
{:ok, {:new, actor}}
{:ok, existing_actor} ->
Logger.info("Updating existing actor #{actor_data["name"]}")
{:ok, updated_act} = Actors.update_actor(existing_actor, actor_attrs, temp_admin_subject)
{:ok, {:existing, updated_act}}
end
end)
|> Ecto.Multi.run({:actor_identity, slug, external_id}, fn repo, changes ->
email_provider = changes[{:email_provider, slug}]
case Map.get(changes, {:actor, slug, external_id}) do
{:new, actor} ->
Logger.info("Creating actor email identity")
Auth.create_identity(actor, email_provider, %{
provider_identifier: actor_data["email"],
provider_identifier_confirmation: actor_data["email"]
})
{:existing, actor} ->
Logger.info("Updating actor email identity")
{:ok, identity} = Auth.Identity.Query.not_deleted()
|> Auth.Identity.Query.by_actor_id(actor.id)
|> Auth.Identity.Query.by_provider_id(email_provider.id)
|> Repo.fetch(Auth.Identity.Query, [])
{:ok, identity |> Ecto.Changeset.change(%{
provider_identifier: actor_data["email"]
}) |> repo.update!()}
end
end)
end)
# Create or update providers
multi = Enum.reduce(account_data["auth"] || %{}, multi, fn {external_id, provider_data}, multi ->
Ecto.Multi.run(multi, {:provider, slug, external_id}, fn repo, changes ->
provider_attrs = %{
name: provider_data["name"],
adapter: String.to_atom(provider_data["adapter"]),
adapter_config: provider_data["adapter_config"]
}
{_, account} = changes[{:account, slug}]
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
uuid = UuidMapping.get_entity(slug, "providers", external_id)
case uuid && Auth.fetch_provider_by_id(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
nil ->
Logger.info("Creating new provider #{provider_data["name"]}")
{:ok, provider} = Auth.create_provider(account, provider_attrs)
UuidMapping.update_entities(slug, "providers", %{external_id => provider.id})
{:ok, provider}
{:ok, existing} ->
Logger.info("Updating existing provider #{provider_data["name"]}")
{:ok, existing |> Ecto.Changeset.change(provider_attrs) |> repo.update!()}
end
end)
end)
# Create or update gateway_groups
multi = Enum.reduce(account_data["gatewayGroups"] || %{}, multi, fn {external_id, gateway_group_data}, multi ->
Ecto.Multi.run(multi, {:gateway_group, slug, external_id}, fn _repo, changes ->
gateway_group_attrs = %{
name: gateway_group_data["name"],
tokens: [%{}]
}
{_, account} = changes[{:account, slug}]
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
uuid = UuidMapping.get_entity(slug, "gateway_groups", external_id)
case uuid && Gateways.fetch_group_by_id(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
nil ->
Logger.info("Creating new gateway group #{gateway_group_data["name"]}")
gateway_group = account
|> Gateways.Group.Changeset.create(gateway_group_attrs, temp_admin_subject)
|> Repo.insert!()
UuidMapping.update_entities(slug, "gateway_groups", %{external_id => gateway_group.id})
{:ok, gateway_group}
{:ok, existing} ->
# Nothing to update
{:ok, existing}
end
end)
end)
# Create or update relay_groups
multi = Enum.reduce(account_data["relayGroups"] || %{}, multi, fn {external_id, relay_group_data}, multi ->
Ecto.Multi.run(multi, {:relay_group, slug, external_id}, fn _repo, changes ->
relay_group_attrs = %{
name: relay_group_data["name"]
}
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
uuid = UuidMapping.get_entity(slug, "relay_groups", external_id)
existing_relay_group = uuid && Relays.fetch_group_by_id(uuid, temp_admin_subject)
case existing_relay_group do
v when v in [nil, {:error, :not_found}] ->
Logger.info("Creating new relay group #{relay_group_data["name"]}")
{:ok, relay_group} = Relays.create_group(relay_group_attrs, temp_admin_subject)
UuidMapping.update_entities(slug, "relay_groups", %{external_id => relay_group.id})
{:ok, relay_group}
{:ok, existing} ->
# Nothing to update
{:ok, existing}
end
end)
end)
# Create or update actor_groups
multi = Enum.reduce(account_data["groups"] || %{}, multi, fn {external_id, actor_group_data}, multi ->
Ecto.Multi.run(multi, {:actor_group, slug, external_id}, fn _repo, changes ->
actor_group_attrs = %{
name: actor_group_data["name"],
type: :static
}
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
uuid = UuidMapping.get_entity(slug, "actor_groups", external_id)
case uuid && Actors.fetch_group_by_id(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
nil ->
Logger.info("Creating new actor group #{actor_group_data["name"]}")
{:ok, actor_group} = Actors.create_group(actor_group_attrs, temp_admin_subject)
UuidMapping.update_entities(slug, "actor_groups", %{external_id => actor_group.id})
{:ok, actor_group}
{:ok, existing} ->
# Nothing to update
{:ok, existing}
end
end)
|> Ecto.Multi.run({:actor_group_members, slug, external_id}, fn repo, changes ->
{_, account} = changes[{:account, slug}]
group_uuid = UuidMapping.get_entity(slug, "actor_groups", external_id)
memberships =
Actors.Membership.Query.all()
|> Actors.Membership.Query.by_group_id(group_uuid)
|> Actors.Membership.Query.returning_all()
|> Repo.all()
existing_members = Enum.map(memberships, fn membership -> membership.actor_id end)
desired_members = Enum.map(actor_group_data["members"] || [], fn member ->
uuid = UuidMapping.get_entity(slug, "actors", member)
if uuid == nil do
raise "Cannot find provisioned actor #{member} to add to group"
end
uuid
end)
missing_members = desired_members -- existing_members
untracked_members = existing_members -- desired_members
Logger.info("Updating members for actor group #{external_id}")
Enum.each(missing_members || [], fn actor_uuid ->
Logger.info("Adding member #{external_id}")
Actors.Membership.Changeset.upsert(account.id, %Actors.Membership{}, %{
group_id: group_uuid,
actor_id: actor_uuid
})
|> repo.insert!()
end)
if actor_group_data["forceMembers"] == true do
# Remove untracked members
to_delete = Enum.map(untracked_members, fn actor_uuid -> {group_uuid, actor_uuid} end)
if to_delete != [] do
Actors.Membership.Query.by_group_id_and_actor_id({:in, to_delete})
|> repo.delete_all()
end
end
{:ok, nil}
end)
end)
# Create or update resources
multi = Enum.reduce(account_data["resources"] || %{}, multi, fn {external_id, resource_data}, multi ->
Ecto.Multi.run(multi, {:resource, slug, external_id}, fn _repo, changes ->
resource_attrs = %{
type: String.to_atom(resource_data["type"]),
name: resource_data["name"],
address: resource_data["address"],
address_description: resource_data["address_description"],
connections: Enum.map(resource_data["gatewayGroups"] || [], fn group ->
%{gateway_group_id: UuidMapping.get_entity(slug, "gateway_groups", group)}
end),
filters: Enum.map(resource_data["filters"] || [], fn filter ->
%{
ports: filter["ports"] || [],
protocol: String.to_atom(filter["protocol"])
}
end)
}
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
uuid = UuidMapping.get_entity(slug, "resources", external_id)
case uuid && fetch_resource(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
nil ->
Logger.info("Creating new resource #{resource_data["name"]}")
{:ok, resource} = Resources.create_resource(resource_attrs, temp_admin_subject)
UuidMapping.update_entities(slug, "resources", %{external_id => resource.id})
{:ok, resource}
{:ok, existing} ->
existing = Repo.preload(existing, :connections)
Logger.info("Updating existing resource #{resource_data["name"]}")
only_updated_attrs = resource_attrs
|> Enum.reject(fn {key, value} ->
case key do
# Compare connections by gateway_group_id only
:connections -> value == Enum.map(existing.connections || [], fn conn -> Map.take(conn, [:gateway_group_id]) end)
# Compare filters by ports and protocol only
:filters -> value == Enum.map(existing.filters || [], fn filter -> Map.take(filter, [:ports, :protocol]) end)
_ -> Map.get(existing, key) == value
end
end)
|> Enum.into(%{})
if only_updated_attrs == %{} do
{:ok, existing}
else
resource = case existing |> Resources.update_resource(resource_attrs, temp_admin_subject) do
{:replaced, _old, new} ->
UuidMapping.update_entities(slug, "resources", %{external_id => new.id})
new
{:updated, value} -> value
x -> x
end
{:ok, resource}
end
end
end)
end)
# Create or update policies
multi = Enum.reduce(account_data["policies"] || %{}, multi, fn {external_id, policy_data}, multi ->
Ecto.Multi.run(multi, {:policy, slug, external_id}, fn _repo, changes ->
policy_attrs = %{
description: policy_data["description"],
actor_group_id: UuidMapping.get_entity(slug, "actor_groups", policy_data["group"]),
resource_id: UuidMapping.get_entity(slug, "resources", policy_data["resource"])
}
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
uuid = UuidMapping.get_entity(slug, "policies", external_id)
case uuid && fetch_policy(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
nil ->
Logger.info("Creating new policy #{policy_data["name"]}")
{:ok, policy} = Policies.create_policy(policy_attrs, temp_admin_subject)
UuidMapping.update_entities(slug, "policies", %{external_id => policy.id})
{:ok, policy}
{:ok, existing} ->
Logger.info("Updating existing policy #{policy_data["name"]}")
only_updated_attrs = policy_attrs
|> Enum.reject(fn {key, value} -> Map.get(existing, key) == value end)
|> Enum.into(%{})
if only_updated_attrs == %{} do
{:ok, existing}
else
policy = case existing |> Policies.update_policy(policy_attrs, temp_admin_subject) do
{:replaced, _old, new} ->
UuidMapping.update_entities(slug, "policies", %{external_id => new.id})
new
{:updated, value} -> value
x -> x
end
{:ok, policy}
end
end
end)
end)
# Clean up temporary admin after all operations
multi |> Ecto.Multi.run({:cleanup_temp_admin, slug}, fn _repo, changes ->
{temp_admin_subject, temp_admin_actor, temp_admin_actor_email_identity, temp_admin_actor_token} =
changes[{:temp_admin, slug}]
cleanup_temp_admin(temp_admin_actor, temp_admin_actor_email_identity, temp_admin_actor_token, temp_admin_subject)
{:ok, :cleaned}
end)
end)
|> Ecto.Multi.run({:save_state}, fn _repo, _changes ->
# Save all UUID mappings to disk.
UuidMapping.save()
{:ok, :saved}
end)
case Repo.transaction(multi) do
{:ok, _result} ->
Logger.info("Provisioning completed successfully")
{:error, step, reason, _changes} ->
Logger.error("Provisioning failed at step #{inspect(step)}, no changes were applied: #{inspect(reason)}")
end
end
end
Provision.provision()
@@ -0,0 +1,202 @@
{
lib,
pkgs,
config,
...
}:
let
inherit (lib)
boolToString
getExe
mkEnableOption
mkIf
mkOption
mkPackageOption
types
;
cfg = config.services.firezone.relay;
in
{
options = {
services.firezone.relay = {
enable = mkEnableOption "the firezone relay server";
package = mkPackageOption pkgs "firezone-relay" { };
name = mkOption {
type = types.str;
example = "My relay";
description = "The name of this gateway as shown in firezone";
};
publicIpv4 = mkOption {
type = types.nullOr types.str;
default = null;
description = "The public ipv4 address of this relay";
};
publicIpv6 = mkOption {
type = types.nullOr types.str;
default = null;
description = "The public ipv6 address of this relay";
};
openFirewall = mkOption {
type = types.bool;
default = true;
description = "Opens up the main STUN port and the TURN allocation range.";
};
port = mkOption {
type = types.port;
default = 3478;
description = "The port to listen on for STUN messages";
};
lowestPort = mkOption {
type = types.port;
default = 49152;
description = "The lowest port to use in TURN allocation";
};
highestPort = mkOption {
type = types.port;
default = 65535;
description = "The highest port to use in TURN allocation";
};
apiUrl = mkOption {
type = types.strMatching "^wss://.+/$";
example = "wss://firezone.example.com/api/";
description = ''
The URL of your firezone server's API. This should be the same
as your server's setting for {option}`services.firezone.server.settings.api.externalUrl`,
but with `wss://` instead of `https://`.
'';
};
tokenFile = mkOption {
type = types.path;
example = "/run/secrets/firezone-relay-token";
description = ''
A file containing the firezone relay token. Do not use a nix-store path here
as it will make the token publicly readable!
This file will be passed via systemd credentials, it should only be accessible
by the root user.
'';
};
logLevel = mkOption {
type = types.str;
default = "info";
description = ''
The log level for the firezone application. See
[RUST_LOG](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)
for the format.
'';
};
enableTelemetry = mkEnableOption "telemetry";
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.publicIpv4 != null || cfg.publicIpv6 != null;
message = "At least one of `services.firezone.relay.publicIpv4` and `services.firezone.relay.publicIpv6` must be set";
}
];
networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ cfg.port ];
networking.firewall.allowedUDPPortRanges = mkIf cfg.openFirewall [
{
from = cfg.lowestPort;
to = cfg.highestPort;
}
];
systemd.services.firezone-relay = {
description = "relay service for the Firezone zero-trust access platform";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.util-linux ];
script = ''
# If FIREZONE_ID is not given by the user, use a persisted (or newly generated) uuid.
if [[ -z "''${FIREZONE_ID:-}" ]]; then
if [[ ! -e relay_id ]]; then
uuidgen -r > relay_id
fi
export FIREZONE_ID=$(< relay_id)
fi
export FIREZONE_TOKEN=$(< "$CREDENTIALS_DIRECTORY/firezone-token")
exec ${getExe cfg.package}
'';
environment = {
FIREZONE_API_URL = cfg.apiUrl;
FIREZONE_NAME = cfg.name;
FIREZONE_TELEMETRY = boolToString cfg.enableTelemetry;
PUBLIC_IP4_ADDR = cfg.publicIpv4;
PUBLIC_IP6_ADDR = cfg.publicIpv6;
LISTEN_PORT = toString cfg.port;
LOWEST_PORT = toString cfg.lowestPort;
HIGHEST_PORT = toString cfg.highestPort;
RUST_LOG = cfg.logLevel;
LOG_FORMAT = "human";
};
serviceConfig = {
Type = "exec";
DynamicUser = true;
User = "firezone-relay";
LoadCredential = [ "firezone-token:${cfg.tokenFile}" ];
StateDirectory = "firezone-relay";
WorkingDirectory = "/var/lib/firezone-relay";
Restart = "on-failure";
RestartSec = 10;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = "@system-service";
UMask = "077";
};
};
};
meta.maintainers = with lib.maintainers; [
oddlama
patrickdag
];
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,232 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.services.prefect;
inherit (lib.types)
bool
str
enum
path
attrsOf
nullOr
submodule
port
;
in
{
options.services.prefect = {
enable = lib.mkOption {
type = bool;
default = false;
description = "enable prefect server and worker services";
};
package = lib.mkPackageOption pkgs "prefect" { };
host = lib.mkOption {
type = str;
default = "127.0.0.1";
example = "0.0.0.0";
description = "Prefect server host";
};
port = lib.mkOption {
type = port;
default = 4200;
description = "Prefect server port";
};
dataDir = lib.mkOption {
type = path;
default = "/var/lib/prefect-server";
description = ''
Specify the directory for Prefect.
'';
};
database = lib.mkOption {
type = enum [
"sqlite"
"postgres"
];
default = "sqlite";
description = "which database to use for prefect server: sqlite or postgres";
};
databaseHost = lib.mkOption {
type = str;
default = "localhost";
description = "database host for postgres only";
};
databasePort = lib.mkOption {
type = str;
default = "5432";
description = "database port for postgres only";
};
databaseName = lib.mkOption {
type = str;
default = "prefect";
description = "database name for postgres only";
};
databaseUser = lib.mkOption {
type = str;
default = "postgres";
description = "database user for postgres only";
};
databasePasswordFile = lib.mkOption {
type = nullOr str;
default = null;
description = ''
path to a file containing e.g.:
DBPASSWORD=supersecret
stored outside the nix store, read by systemd as EnvironmentFile.
'';
};
# now define workerPools as an attribute set of submodules,
# each key is the pool name, and the submodule has an installPolicy
workerPools = lib.mkOption {
type = attrsOf (submodule {
options = {
installPolicy = lib.mkOption {
type = enum [
"always"
"if-not-present"
"never"
"prompt"
];
default = "always";
description = "install policy for the worker (always, if-not-present, never, prompt)";
};
};
});
default = { };
description = ''
define a set of worker pools with submodule config. example:
workerPools.my-pool = {
installPolicy = "never";
};
'';
};
baseUrl = lib.mkOption {
type = nullOr str;
default = null;
description = "external url when served by a reverse proxy, e.g. https://example.com/prefect";
};
};
config = lib.mkIf cfg.enable {
# define systemd.services as the server plus any worker definitions
systemd.services =
{
"prefect-server" = {
description = "prefect server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
DynamicUser = true;
StateDirectory = "prefect-server";
# TODO all my efforts to setup the database url
# have failed with some unable to open file
Environment = [
"PREFECT_HOME=%S/prefect-server"
"PREFECT_UI_STATIC_DIRECTORY=%S/prefect-server"
"PREFECT_SERVER_ANALYTICS_ENABLED=off"
"PREFECT_UI_API_URL=${cfg.baseUrl}/api"
"PREFECT_UI_URL=${cfg.baseUrl}"
];
EnvironmentFile =
if cfg.database == "postgres" && cfg.databasePasswordFile != null then
[ cfg.databasePasswordFile ]
else
[ ];
# ReadWritePaths = [ cfg.dataDir ];
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
NoNewPrivileges = true;
MemoryDenyWriteExecute = true;
LockPersonality = true;
CapabilityBoundingSet = [ ];
AmbientCapabilities = [ ];
RestrictSUIDSGID = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
MemoryAccounting = true;
CPUAccounting = true;
ExecStart = "${pkgs.prefect}/bin/prefect server start --host ${cfg.host} --port ${toString cfg.port}";
Restart = "always";
WorkingDirectory = cfg.dataDir;
};
};
}
// lib.concatMapAttrs (poolName: poolCfg: {
# return a partial attr set with one key: "prefect-worker-..."
"prefect-worker-${poolName}" = {
description = "prefect worker for pool '${poolName}'";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment.systemPackages = cfg.package;
serviceConfig = {
DynamicUser = true;
StateDirectory = "prefect-worker-${poolName}";
Environment = [
"PREFECT_HOME=%S/prefect-worker-${poolName}"
"PREFECT_API_URL=${cfg.baseUrl}/api"
];
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
NoNewPrivileges = true;
MemoryDenyWriteExecute = true;
LockPersonality = true;
CapabilityBoundingSet = [ ];
AmbientCapabilities = [ ];
RestrictSUIDSGID = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
MemoryAccounting = true;
CPUAccounting = true;
ExecStart = ''
${pkgs.prefect}/bin/prefect worker start \
--pool ${poolName} \
--type process \
--install-policy ${poolCfg.installPolicy}
'';
Restart = "always";
};
};
}) cfg.workerPools;
};
}
+13 -6
View File
@@ -75,9 +75,12 @@ in
);
# Hardening
AmbientCapabilities = "";
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
DevicePolicy = "closed";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
@@ -91,15 +94,19 @@ in
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RemoveIPC = true;
RestrictAddressFamilies = [ "AF_INET AF_INET6 AF_UNIX" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
"setrlimit"
];
UMask = "0077";
};
};
+11 -6
View File
@@ -107,9 +107,11 @@ in
ExecStart = lib.getExe cfg.package;
# Hardening
AmbientCapabilities = "";
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
DevicePolicy = "closed";
LockPersonality = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
@@ -123,15 +125,18 @@ in
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RemoveIPC = true;
RestrictAddressFamilies = [ "AF_INET AF_INET6 AF_UNIX AF_NETLINK" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
};
};
};
+9
View File
@@ -19,6 +19,7 @@ let
kernel = config.system.modulesTree;
firmware = config.hardware.firmware;
allowMissing = false;
inherit (config.boot.initrd) extraFirmwarePaths;
};
@@ -484,6 +485,14 @@ in
'';
};
boot.initrd.extraFirmwarePaths = mkOption {
default = [ ];
type = types.listOf types.str;
description = ''
Other firmware files (relative to `"''${config.hardware.firmware}/lib/firmware"`) to include in the final initrd we are building.
'';
};
boot.initrd.checkJournalingFS = mkOption {
default = true;
type = types.bool;
+4 -2
View File
@@ -104,7 +104,7 @@ let
"sleep.target"
"hybrid-sleep.target"
"systemd-hibernate.service"
"systemd-hibernate-clear.service"
] ++ (lib.optional cfg.package.withEfi "systemd-hibernate-clear.service") ++ [
"systemd-hybrid-sleep.service"
"systemd-suspend.service"
"systemd-suspend-then-hibernate.service"
@@ -130,11 +130,13 @@ let
"systemd-ask-password-wall.service"
# Varlink APIs
] ++ lib.optionals cfg.package.withBootloader [
"systemd-bootctl@.service"
"systemd-bootctl.socket"
] ++ [
"systemd-creds@.service"
"systemd-creds.socket"
] ++ lib.optional cfg.package.withTpm2Tss [
] ++ lib.optional cfg.package.withTpm2Units [
"systemd-pcrlock@.service"
"systemd-pcrlock.socket"
] ++ [
+6 -4
View File
@@ -105,6 +105,7 @@ let
kernel = config.system.modulesTree;
firmware = config.hardware.firmware;
allowMissing = false;
inherit (config.boot.initrd) extraFirmwarePaths;
};
initrdBinEnv = pkgs.buildEnv {
@@ -703,10 +704,11 @@ in
"|stage1panic"
];
};
script = ''
echo c > /proc/sysrq-trigger
'';
serviceConfig.Type = "oneshot";
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.coreutils}/bin/echo c";
StandardOutput = "file:/proc/sysrq-trigger";
};
};
};
};
+4 -4
View File
@@ -27,13 +27,13 @@
options = {
systemd.tpm2.enable = lib.mkEnableOption "systemd TPM2 support" // {
default = config.systemd.package.withTpm2Tss;
defaultText = "systemd.package.withTpm2Tss";
default = config.systemd.package.withTpm2Units;
defaultText = "systemd.package.withTpm2Units";
};
boot.initrd.systemd.tpm2.enable = lib.mkEnableOption "systemd initrd TPM2 support" // {
default = config.boot.initrd.systemd.package.withTpm2Tss;
defaultText = "boot.initrd.systemd.package.withTpm2Tss";
default = config.boot.initrd.systemd.package.withTpm2Units;
defaultText = "boot.initrd.systemd.package.withTpm2Units";
};
};
+10 -6
View File
@@ -1,6 +1,6 @@
# Systemd services for docker.
{ config, lib, pkgs, ... }:
{ config, lib, utils, pkgs, ... }:
with lib;
@@ -271,11 +271,15 @@ in
restartIfChanged = false;
unitConfig.X-StopOnRemoval = false;
serviceConfig.Type = "oneshot";
script = ''
${cfg.package}/bin/docker system prune -f ${toString cfg.autoPrune.flags}
'';
serviceConfig = {
Type = "oneshot";
ExecStart = utils.escapeSystemdExecArgs ([
(lib.getExe cfg.package)
"system"
"prune"
"-f"
] ++ cfg.autoPrune.flags);
};
startAt = optional cfg.autoPrune.enable cfg.autoPrune.dates;
after = [ "docker.service" ];
@@ -178,7 +178,6 @@ let
exec ${config.systemd.package}/bin/systemd-nspawn \
--keep-unit \
-M "$INSTANCE" -D "$root" "''${extraFlags[@]}" \
$EXTRA_NSPAWN_FLAGS \
--notify-ready=yes \
--kill-signal=SIGRTMIN+3 \
--bind-ro=/nix/store:/nix/store$NIX_BIND_OPT \
@@ -203,6 +202,7 @@ let
${optionalString (cfg.tmpfs != null && cfg.tmpfs != [])
''--tmpfs=${concatStringsSep " --tmpfs=" cfg.tmpfs}''
} \
$EXTRA_NSPAWN_FLAGS \
${containerInit cfg} "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/init"
'';
@@ -1,4 +1,4 @@
{ config, lib, pkgs, ... }:
{ config, lib, utils, pkgs, ... }:
let
cfg = config.virtualisation.podman;
json = pkgs.formats.json { };
@@ -202,11 +202,15 @@ in
restartIfChanged = false;
unitConfig.X-StopOnRemoval = false;
serviceConfig.Type = "oneshot";
script = ''
${cfg.package}/bin/podman system prune -f ${toString cfg.autoPrune.flags}
'';
serviceConfig = {
Type = "oneshot";
ExecStart = utils.escapeSystemdExecArgs ([
(lib.getExe cfg.package)
"system"
"prune"
"-f"
] ++ cfg.autoPrune.flags);
};
startAt = lib.optional cfg.autoPrune.enable cfg.autoPrune.dates;
after = [ "podman.service" ];
+3 -1
View File
@@ -353,7 +353,7 @@ in {
early-mount-options = handleTest ./early-mount-options.nix {};
ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {};
ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {};
echoip = handleTest ./echoip.nix {};
echoip = runTest ./echoip.nix;
ecryptfs = handleTest ./ecryptfs.nix {};
fscrypt = handleTest ./fscrypt.nix {};
fastnetmon-advanced = runTest ./fastnetmon-advanced.nix;
@@ -425,6 +425,7 @@ in {
firewall = handleTest ./firewall.nix { nftables = false; };
firewall-nftables = handleTest ./firewall.nix { nftables = true; };
fish = runTest ./fish.nix;
firezone = handleTest ./firezone/firezone.nix {};
flannel = handleTestOn ["x86_64-linux"] ./flannel.nix {};
flaresolverr = handleTest ./flaresolverr.nix {};
flood = handleTest ./flood.nix {};
@@ -969,6 +970,7 @@ in {
pppd = handleTest ./pppd.nix {};
predictable-interface-names = handleTest ./predictable-interface-names.nix {};
pretalx = runTest ./web-apps/pretalx.nix;
prefect = runTest ./prefect.nix;
pretix = runTest ./web-apps/pretix.nix;
printing-socket = handleTest ./printing.nix { socket = true; listenTcp = true; };
printing-service = handleTest ./printing.nix { socket = false; listenTcp = true; };
+23 -24
View File
@@ -1,29 +1,28 @@
import ./make-test-python.nix (
{ lib, ... }:
{
name = "echoip";
meta.maintainers = with lib.maintainers; [ defelo ];
{ lib, ... }:
nodes.machine = {
services.echoip = {
enable = true;
virtualHost = "echoip.local";
};
{
name = "echoip";
meta.maintainers = with lib.maintainers; [ defelo ];
networking.hosts = {
"127.0.0.1" = [ "echoip.local" ];
"::1" = [ "echoip.local" ];
};
nodes.machine = {
services.echoip = {
enable = true;
virtualHost = "echoip.local";
};
testScript = ''
machine.wait_for_unit("echoip.service")
machine.wait_for_open_port(8080)
networking.hosts = {
"127.0.0.1" = [ "echoip.local" ];
"::1" = [ "echoip.local" ];
};
};
resp = machine.succeed("curl -4 http://echoip.local/ip")
assert resp.strip() == "127.0.0.1"
resp = machine.succeed("curl -6 http://echoip.local/ip")
assert resp.strip() == "::1"
'';
}
)
testScript = ''
machine.wait_for_unit("echoip.service")
machine.wait_for_open_port(8080)
resp = machine.succeed("curl -4 http://echoip.local/ip")
assert resp.strip() == "127.0.0.1"
resp = machine.succeed("curl -6 http://echoip.local/ip")
assert resp.strip() == "::1"
'';
}
+86
View File
@@ -0,0 +1,86 @@
alias Domain.{Repo, Accounts, Auth, Actors, Tokens}
mappings = case File.read("provision-uuids.json") do
{:ok, content} ->
case Jason.decode(content) do
{:ok, mapping} -> mapping
_ -> %{"accounts" => %{}}
end
_ -> %{"accounts" => %{}}
end
IO.puts("INFO: Fetching account")
{:ok, account} = Accounts.fetch_account_by_id_or_slug("main")
IO.puts("INFO: Fetching email provider")
{:ok, email_provider} = Auth.Provider.Query.not_disabled()
|> Auth.Provider.Query.by_adapter(:email)
|> Auth.Provider.Query.by_account_id(account.id)
|> Repo.fetch(Auth.Provider.Query, [])
temp_admin_actor_email = "firezone-provision@localhost.local"
temp_admin_actor_context = %Auth.Context{
type: :browser,
user_agent: "Unspecified/0.0",
remote_ip: {127, 0, 0, 1},
remote_ip_location_region: "N/A",
remote_ip_location_city: "N/A",
remote_ip_location_lat: 0.0,
remote_ip_location_lon: 0.0
}
{:ok, temp_admin_actor} =
Actors.create_actor(account, %{
type: :account_admin_user,
name: "Token Provisioning"
})
{:ok, temp_admin_actor_email_identity} =
Auth.create_identity(temp_admin_actor, email_provider, %{
provider_identifier: temp_admin_actor_email,
provider_identifier_confirmation: temp_admin_actor_email
})
{:ok, temp_admin_actor_token} =
Auth.create_token(temp_admin_actor_email_identity, temp_admin_actor_context, "temporarynonce", DateTime.utc_now() |> DateTime.add(1, :hour))
{:ok, temp_admin_subject} =
Auth.build_subject(temp_admin_actor_token, temp_admin_actor_context)
{:ok, relay_group_token} =
Tokens.create_token(%{
"type" => :relay_group,
"expires_at" => DateTime.utc_now() |> DateTime.add(1, :hour),
"secret_fragment" => Domain.Crypto.random_token(32, encoder: :hex32),
"relay_group_id" => get_in(mappings, ["accounts", "main", "relay_groups", "my-relays"])
})
relay_group_encoded_token = Tokens.encode_fragment!(relay_group_token)
IO.puts("Created relay token: #{relay_group_encoded_token}")
File.write("relay_token.txt", relay_group_encoded_token)
{:ok, gateway_group_token} =
Tokens.create_token(%{
"type" => :gateway_group,
"expires_at" => DateTime.utc_now() |> DateTime.add(1, :hour),
"secret_fragment" => Domain.Crypto.random_token(32, encoder: :hex32),
"account_id" => get_in(mappings, ["accounts", "main", "id"]),
"gateway_group_id" => get_in(mappings, ["accounts", "main", "gateway_groups", "site"])
}, temp_admin_subject)
gateway_group_encoded_token = Tokens.encode_fragment!(gateway_group_token)
IO.puts("Created gateway group token: #{gateway_group_encoded_token}")
File.write("gateway_token.txt", gateway_group_encoded_token)
{:ok, service_account_actor_token} =
Tokens.create_token(%{
"type" => :client,
"expires_at" => DateTime.utc_now() |> DateTime.add(1, :hour),
"secret_fragment" => Domain.Crypto.random_token(32, encoder: :hex32),
"account_id" => get_in(mappings, ["accounts", "main", "id"]),
"actor_id" => get_in(mappings, ["accounts", "main", "actors", "client"])
})
service_account_actor_encoded_token = Tokens.encode_fragment!(service_account_actor_token)
IO.puts("Created service actor token: #{service_account_actor_encoded_token}")
File.write("client_token.txt", service_account_actor_encoded_token)
+349
View File
@@ -0,0 +1,349 @@
import ../make-test-python.nix (
{ pkgs, ... }:
let
certs = import ../common/acme/server/snakeoil-certs.nix;
domain = certs.domain;
in
{
name = "firezone";
meta.maintainers = with pkgs.lib.maintainers; [ oddlama ];
nodes = {
server =
{
config,
lib,
pkgs,
...
}:
{
security.pki.certificateFiles = [ certs.ca.cert ];
networking.extraHosts = ''
${config.networking.primaryIPAddress} ${domain}
${config.networking.primaryIPv6Address} ${domain}
'';
networking.firewall.allowedTCPPorts = [
80
443
];
services.nginx = {
enable = true;
virtualHosts.${domain} = {
sslCertificate = certs.${domain}.cert;
sslCertificateKey = certs.${domain}.key;
};
};
services.firezone.server = {
enable = true;
enableLocalDB = true;
nginx.enable = true;
# Doesn't need to work for this test, but needs to be configured
# otherwise the server will not start.
smtp = {
from = "firezone@example.com";
host = "mail.localhost";
port = 465;
implicitTls = true;
username = "firezone@example.com";
passwordFile = pkgs.writeText "tmpmailpasswd" "supermailpassword";
};
provision = {
enable = true;
accounts.main = {
name = "My Account";
relayGroups.my-relays.name = "Relays";
gatewayGroups.site.name = "Site";
actors = {
admin = {
type = "account_admin_user";
name = "Admin";
email = "admin@example.com";
};
client = {
type = "service_account";
name = "A client";
email = "client@example.com";
};
};
resources.res1 = {
type = "dns";
name = "Dns Resource";
address = "resource.example.com";
gatewayGroups = [ "site" ];
filters = [
{ protocol = "icmp"; }
{
protocol = "tcp";
ports = [ 80 ];
}
];
};
resources.res2 = {
type = "ip";
name = "Ip Resource";
address = "172.20.2.1";
gatewayGroups = [ "site" ];
};
resources.res3 = {
type = "cidr";
name = "Cidr Resource";
address = "172.20.1.0/24";
gatewayGroups = [ "site" ];
};
policies.pol1 = {
description = "Allow anyone res1 access";
group = "everyone";
resource = "res1";
};
policies.pol2 = {
description = "Allow anyone res2 access";
group = "everyone";
resource = "res2";
};
policies.pol3 = {
description = "Allow anyone res3 access";
group = "everyone";
resource = "res3";
};
};
};
api.externalUrl = "https://${domain}/api/";
web.externalUrl = "https://${domain}/";
};
systemd.services.firezone-server-domain.postStart = lib.mkAfter ''
${lib.getExe config.services.firezone.server.domain.package} rpc 'Code.eval_file("${./create-tokens.exs}")'
'';
};
relay =
{
nodes,
config,
lib,
...
}:
{
security.pki.certificateFiles = [ certs.ca.cert ];
networking.extraHosts = ''
${nodes.server.networking.primaryIPAddress} ${domain}
${nodes.server.networking.primaryIPv6Address} ${domain}
'';
services.firezone.relay = {
enable = true;
logLevel = "debug";
name = "test-relay";
apiUrl = "wss://${domain}/api/";
tokenFile = "/tmp/shared/relay_token.txt";
publicIpv4 = config.networking.primaryIPAddress;
publicIpv6 = config.networking.primaryIPv6Address;
openFirewall = true;
};
# Don't auto-start so we can wait until the token was provisioned
systemd.services.firezone-relay.wantedBy = lib.mkForce [ ];
};
# A resource that is only connected to the gateway,
# allowing us to confirm the VPN works
resource = {
virtualisation.vlans = [
1
2
];
networking.interfaces.eth1.ipv4.addresses = [
{
address = "172.20.1.1";
prefixLength = 24;
}
];
networking.interfaces.eth2.ipv4.addresses = [
{
address = "172.20.2.1";
prefixLength = 24;
}
];
networking.firewall.allowedTCPPorts = [
80
];
services.nginx = {
enable = true;
virtualHosts = {
"localhost" = {
default = true;
locations."/".extraConfig = ''
return 200 'greetings from the resource';
add_header Content-Type text/plain;
'';
};
};
};
};
gateway =
{
nodes,
lib,
...
}:
{
virtualisation.vlans = [
1
2
];
networking = {
interfaces.eth1.ipv4.addresses = [
{
address = "172.20.1.2";
prefixLength = 24;
}
];
interfaces.eth2.ipv4.addresses = [
{
address = "172.20.2.2";
prefixLength = 24;
}
];
firewall.enable = false;
nftables.enable = true;
nftables.tables."filter".family = "inet";
nftables.tables."filter".content = ''
chain incoming {
type filter hook input priority 0; policy accept;
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
meta protocol ip iifname "tun-firezone" oifname { "eth1", "eth2" } masquerade random
}
chain forward {
type filter hook forward priority 0; policy drop;
iifname "tun-firezone" accept
oifname "tun-firezone" accept
}
chain output {
type filter hook output priority 0; policy accept;
}
'';
};
boot.kernel.sysctl."net.ipv4.ip_forward" = "1";
# boot.kernel.sysctl."net.ipv4.conf.all.src_valid_mark" = "1";
boot.kernel.sysctl."net.ipv6.conf.default.forwarding" = "1";
boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = "1";
security.pki.certificateFiles = [ certs.ca.cert ];
networking.extraHosts = ''
${nodes.server.networking.primaryIPAddress} ${domain}
${nodes.server.networking.primaryIPv6Address} ${domain}
172.20.1.1 resource.example.com
'';
services.firezone.gateway = {
enable = true;
logLevel = "debug";
name = "test-gateway";
apiUrl = "wss://${domain}/api/";
tokenFile = "/tmp/shared/gateway_token.txt";
};
# Don't auto-start so we can wait until the token was provisioned
systemd.services.firezone-gateway.wantedBy = lib.mkForce [ ];
};
client =
{
nodes,
lib,
...
}:
{
security.pki.certificateFiles = [ certs.ca.cert ];
networking.useNetworkd = true;
networking.extraHosts = ''
${nodes.server.networking.primaryIPAddress} ${domain}
${nodes.server.networking.primaryIPv6Address} ${domain}
'';
services.firezone.headless-client = {
enable = true;
logLevel = "debug";
name = "test-client-somebody";
apiUrl = "wss://${domain}/api/";
tokenFile = "/tmp/shared/client_token.txt";
};
# Don't auto-start so we can wait until the token was provisioned
systemd.services.firezone-headless-client.wantedBy = lib.mkForce [ ];
};
};
testScript =
{ ... }:
''
start_all()
with subtest("Start server"):
server.wait_for_unit("firezone.target")
server.wait_until_succeeds("curl -Lsf https://${domain} | grep 'Welcome to Firezone'")
server.wait_until_succeeds("curl -Ls https://${domain}/api | grep 'Not Found'")
# Wait for tokens and copy them to shared folder
server.wait_for_file("/var/lib/private/firezone/relay_token.txt")
server.wait_for_file("/var/lib/private/firezone/gateway_token.txt")
server.wait_for_file("/var/lib/private/firezone/client_token.txt")
server.succeed("cp /var/lib/private/firezone/*_token.txt /tmp/shared")
with subtest("Connect relay"):
relay.succeed("systemctl start firezone-relay")
relay.wait_for_unit("firezone-relay.service")
relay.wait_until_succeeds("journalctl --since -2m --unit firezone-relay.service --grep 'Connected to portal.*${domain}'", timeout=30)
with subtest("Connect gateway"):
gateway.succeed("systemctl start firezone-gateway")
gateway.wait_for_unit("firezone-gateway.service")
gateway.wait_until_succeeds("journalctl --since -2m --unit firezone-gateway.service --grep 'Connected to portal.*${domain}'", timeout=30)
relay.wait_until_succeeds("journalctl --since -2m --unit firezone-relay.service --grep 'Created allocation.*IPv4'", timeout=30)
relay.wait_until_succeeds("journalctl --since -2m --unit firezone-relay.service --grep 'Created allocation.*IPv6'", timeout=30)
# Assert both relay ips are known
gateway.wait_until_succeeds("journalctl --since -2m --unit firezone-gateway.service --grep 'Updated allocation.*relay_ip4.*Some.*relay_ip6.*Some'", timeout=30)
with subtest("Connect headless-client"):
client.succeed("systemctl start firezone-headless-client")
client.wait_for_unit("firezone-headless-client.service")
client.wait_until_succeeds("journalctl --since -2m --unit firezone-headless-client.service --grep 'Connected to portal.*${domain}'", timeout=30)
client.wait_until_succeeds("journalctl --since -2m --unit firezone-headless-client.service --grep 'Tunnel ready'", timeout=30)
with subtest("Check DNS based access"):
# Check that we can access the resource through the VPN via DNS
client.wait_until_succeeds("curl -4 -Lsf http://resource.example.com | grep 'greetings from the resource'")
client.wait_until_succeeds("curl -6 -Lsf http://resource.example.com | grep 'greetings from the resource'")
with subtest("Check CIDR based access"):
# Check that we can access the resource through the VPN via CIDR
client.wait_until_succeeds("ping -c1 -W1 172.20.1.1")
with subtest("Check IP based access"):
# Check that we can access the resource through the VPN via IP
client.wait_until_succeeds("ping -c1 -W1 172.20.2.1")
'';
}
)
+3
View File
@@ -25,7 +25,10 @@ import ./make-test-python.nix (
machine.wait_for_open_port(80)
machine.wait_for_unit("multi-user.target")
# This establishes _something_
machine.succeed("curl -sSf http://localhost")
# The second request creates the database, unsure why both are required
machine.succeed("curl -sSf http://localhost/")
machine.succeed(
"curl -c cookies -sSf -X POST http://localhost/login -d 'username=admin&password=admin'"
+2 -2
View File
@@ -9,8 +9,8 @@
services.paretosecurity.enable = true;
};
# very basic test for now, need to add output asserts
testScript = ''
machine.wait_until_succeeds("paretosecurity check")
(status, out) = machine.execute("paretosecurity check")
assert status == 1, "paretosecurity did not return 1 on failing checks"
'';
}
+27
View File
@@ -0,0 +1,27 @@
{ lib, ... }:
let
mainPort = "4200";
in
{
name = "prefect";
nodes = {
machine =
{ ... }:
{
services.prefect = {
enable = true;
};
};
};
testScript = ''
machine.start()
machine.wait_for_unit("prefect-server.service")
machine.wait_for_open_port("${mainPort}")
'';
meta = with lib.maintainers; {
maintainers = [ happysalada ];
};
}
+13
View File
@@ -1,4 +1,5 @@
{ lib, ... }:
{
name = "zipline";
meta.maintainers = with lib.maintainers; [ defelo ];
@@ -20,6 +21,18 @@
networking.hosts."127.0.0.1" = [ "zipline.local" ];
};
interactive.nodes.machine = {
services.zipline.settings.CORE_HOSTNAME = lib.mkForce "0.0.0.0";
networking.firewall.allowedTCPPorts = [ 8000 ];
virtualisation.forwardPorts = [
{
from = "host";
host.port = 8000;
guest.port = 8000;
}
];
};
testScript = ''
import json
import re
+1 -1
View File
@@ -36,7 +36,7 @@ Before adding a new package, please consider the following questions:
If any of these questions' answer is no, then you should probably not add the package.
This is section describes a general framework of understanding and exceptions might apply.
This section describes a general framework of understanding and exceptions might apply.
Luckily it's pretty easy to maintain your own package set with Nix, which can then be added to the [Nix User Repository](https://github.com/nix-community/nur) project.
+8 -13
View File
@@ -35,13 +35,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "musescore";
version = "4.4.4";
version = "4.5";
src = fetchFromGitHub {
owner = "musescore";
repo = "MuseScore";
rev = "v${finalAttrs.version}";
sha256 = "sha256-/1kAgzmSbnuCqd6YxbaYW2+gE0Gvy373y5VfUK4OVzI=";
sha256 = "sha256-7sD9AAuuDT0+VycKLL19DYdmuSLmt0Uy2NmoKQ1+c3A=";
};
cmakeFlags = [
@@ -127,17 +127,12 @@ stdenv.mkDerivation (finalAttrs: {
qtwayland
];
postInstall =
''
# Remove unneeded bundled libraries and headers
rm -r $out/{include,lib}
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
mkdir -p "$out/Applications"
mv "$out/mscore.app" "$out/Applications/mscore.app"
mkdir -p $out/bin
ln -s $out/Applications/mscore.app/Contents/MacOS/mscore $out/bin/mscore
'';
postInstall = lib.optionalString stdenv.hostPlatform.isDarwin ''
mkdir -p "$out/Applications"
mv "$out/mscore.app" "$out/Applications/mscore.app"
mkdir -p $out/bin
ln -s $out/Applications/mscore.app/Contents/MacOS/mscore $out/bin/mscore
'';
# muse-sounds-manager installs Muse Sounds sampler libMuseSamplerCoreLib.so.
# It requires that argv0 of the calling process ends with "/mscore" or "/MuseScore-4".
@@ -850,6 +850,19 @@ final: prev:
meta.hydraPlatforms = [ ];
};
arshlib-nvim = buildVimPlugin {
pname = "arshlib.nvim";
version = "2024-05-18";
src = fetchFromGitHub {
owner = "arsham";
repo = "arshlib.nvim";
rev = "111fd439268adda206a24b133096893869a50764";
sha256 = "1jmac14w37lybanr8jg4jpi3rkbsjhmz65x5fr7mgd7kagsn3r1n";
};
meta.homepage = "https://github.com/arsham/arshlib.nvim/";
meta.hydraPlatforms = [ ];
};
astrocore = buildVimPlugin {
pname = "astrocore";
version = "2025-02-18";
@@ -6125,6 +6138,19 @@ final: prev:
meta.hydraPlatforms = [ ];
};
indent-tools-nvim = buildVimPlugin {
pname = "indent-tools.nvim";
version = "2023-10-28";
src = fetchFromGitHub {
owner = "arsham";
repo = "indent-tools.nvim";
rev = "31b839d65aa04b568fabe5e100a63cc44ef3f5d5";
sha256 = "0vw3j9plwi6ari5p5hmds257xw0szlj2ddf75mjfj6nfzd93ni0p";
};
meta.homepage = "https://github.com/arsham/indent-tools.nvim/";
meta.hydraPlatforms = [ ];
};
indentLine = buildVimPlugin {
pname = "indentLine";
version = "2023-07-14";
@@ -6,7 +6,6 @@
buildVimPlugin,
callPackage,
fetchFromGitHub,
fetchFromSourcehut,
fetchpatch,
fetchurl,
neovimUtils,
@@ -158,14 +157,6 @@ in
#######################
# Regular overrides
aerial-nvim = super.aerial-nvim.overrideAttrs {
# optional dependencies
nvimSkipModule = [
"lualine.components.aerial"
"telescope._extensions.aerial"
];
};
advanced-git-search-nvim = super.advanced-git-search-nvim.overrideAttrs {
dependencies = with self; [
telescope-nvim
@@ -176,6 +167,14 @@ in
];
};
aerial-nvim = super.aerial-nvim.overrideAttrs {
# optional dependencies
nvimSkipModule = [
"lualine.components.aerial"
"telescope._extensions.aerial"
];
};
agitator-nvim = super.agitator-nvim.overrideAttrs {
dependencies = with self; [
telescope-nvim
@@ -183,6 +182,23 @@ in
];
};
aider-nvim = super.aider-nvim.overrideAttrs {
patches = [
(replaceVars ./patches/aider-nvim/bin.patch { aider = lib.getExe' aider-chat "aider"; })
];
};
animation-nvim = super.animation-nvim.overrideAttrs {
dependencies = [ self.middleclass ];
};
arshlib-nvim = super.arshlib-nvim.overrideAttrs {
dependencies = with self; [
nui-nvim
plenary-nvim
];
};
astrocore = super.astrocore.overrideAttrs {
dependencies = [ self.lazy-nvim ];
};
@@ -200,10 +216,6 @@ in
];
};
animation-nvim = super.animation-nvim.overrideAttrs {
dependencies = [ self.middleclass ];
};
autosave-nvim = super.autosave-nvim.overrideAttrs {
dependencies = [ self.plenary-nvim ];
};
@@ -296,6 +308,10 @@ in
dependencies = [ self.plenary-nvim ];
};
blink-cmp-git = super.blink-cmp-git.overrideAttrs {
dependencies = [ self.plenary-nvim ];
};
blink-emoji-nvim = super.blink-emoji-nvim.overrideAttrs {
dependencies = [ self.blink-cmp ];
};
@@ -304,10 +320,6 @@ in
dependencies = [ self.blink-cmp ];
};
blink-cmp-git = super.blink-cmp-git.overrideAttrs {
dependencies = [ self.plenary-nvim ];
};
blink-pairs = callPackage ./non-generated/blink-pairs { };
bluloco-nvim = super.bluloco-nvim.overrideAttrs {
@@ -578,6 +590,10 @@ in
dependencies = [ self.vim-lsp ];
};
cmp-vimtex = super.cmp-vimtex.overrideAttrs {
checkInputs = [ self.nvim-cmp ];
};
cmp-vimwiki-tags = super.cmp-vimwiki-tags.overrideAttrs {
checkInputs = [ self.nvim-cmp ];
dependencies = [ self.vimwiki ];
@@ -587,10 +603,6 @@ in
checkInputs = [ self.nvim-cmp ];
};
cmp-vimtex = super.cmp-vimtex.overrideAttrs {
checkInputs = [ self.nvim-cmp ];
};
cmp-zsh = super.cmp-zsh.overrideAttrs {
checkInputs = [ self.nvim-cmp ];
dependencies = [ zsh ];
@@ -946,29 +958,14 @@ in
dependencies = [ self.ddc-vim ];
};
ddc-source-lsp = super.ddc-source-lsp.overrideAttrs {
dependencies = [ self.ddc-vim ];
};
ddc-vim = super.ddc-vim.overrideAttrs {
dependencies = [ self.denops-vim ];
};
ddc-filter-sorter_rank = super.ddc-filter-sorter_rank.overrideAttrs {
dependencies = [ self.ddc-vim ];
};
ddc-ui-native = super.ddc-ui-native.overrideAttrs {
ddc-fuzzy = super.ddc-fuzzy.overrideAttrs {
dependencies = [ self.ddc-vim ];
};
ddc-ui-pum = super.ddc-ui-pum.overrideAttrs {
dependencies = with self; [
ddc-vim
pum-vim
];
};
ddc-source-around = super.ddc-source-around.overrideAttrs {
dependencies = [ self.ddc-vim ];
};
@@ -977,10 +974,25 @@ in
dependencies = [ self.ddc-vim ];
};
ddc-fuzzy = super.ddc-fuzzy.overrideAttrs {
ddc-source-lsp = super.ddc-source-lsp.overrideAttrs {
dependencies = [ self.ddc-vim ];
};
ddc-ui-pum = super.ddc-ui-pum.overrideAttrs {
dependencies = with self; [
ddc-vim
pum-vim
];
};
ddc-ui-native = super.ddc-ui-native.overrideAttrs {
dependencies = [ self.ddc-vim ];
};
ddc-vim = super.ddc-vim.overrideAttrs {
dependencies = [ self.denops-vim ];
};
defx-nvim = super.defx-nvim.overrideAttrs {
dependencies = [ self.nvim-yarp ];
};
@@ -1196,18 +1208,6 @@ in
'';
});
fuzzy-nvim = super.fuzzy-nvim.overrideAttrs {
checkInputs = with self; [
# Optional sorters
telescope-zf-native-nvim
];
dependencies = [ self.telescope-fzf-native-nvim ];
nvimSkipModule = [
# TODO: package fzy-lua-native
"fuzzy_nvim.fzy_matcher"
];
};
fugit2-nvim = super.fugit2-nvim.overrideAttrs {
# Requires web-devicons but mini.icons can mock them up
checkInputs = [
@@ -1226,6 +1226,18 @@ in
'';
};
fuzzy-nvim = super.fuzzy-nvim.overrideAttrs {
checkInputs = with self; [
# Optional sorters
telescope-zf-native-nvim
];
dependencies = [ self.telescope-fzf-native-nvim ];
nvimSkipModule = [
# TODO: package fzy-lua-native
"fuzzy_nvim.fzy_matcher"
];
};
fzf-checkout-vim = super.fzf-checkout-vim.overrideAttrs {
# The plugin has a makefile which tries to run tests in a docker container.
# This prevents it.
@@ -1288,6 +1300,18 @@ in
dependencies = [ self.plenary-nvim ];
};
git-conflict-nvim = super.git-conflict-nvim.overrideAttrs {
# TODO: Remove after next fixed version
# https://github.com/akinsho/git-conflict.nvim/issues/103
version = "2.1.0";
src = fetchFromGitHub {
owner = "akinsho";
repo = "git-conflict.nvim";
tag = "v2.1.0";
hash = "sha256-1t0kKxTGLuOvuRkoLgkoqMZpF+oKo8+gMsTdgPsSb+8=";
};
};
git-worktree-nvim = super.git-worktree-nvim.overrideAttrs {
dependencies = [ self.plenary-nvim ];
};
@@ -1363,14 +1387,14 @@ in
];
};
haskell-snippets-nvim = super.haskell-snippets-nvim.overrideAttrs {
dependencies = [ self.luasnip ];
};
haskell-scope-highlighting-nvim = super.haskell-scope-highlighting-nvim.overrideAttrs {
dependencies = [ self.nvim-treesitter ];
};
haskell-snippets-nvim = super.haskell-snippets-nvim.overrideAttrs {
dependencies = [ self.luasnip ];
};
haskell-tools-nvim = neovimUtils.buildNeovimPlugin {
luaAttr = luaPackages.haskell-tools-nvim;
nvimSkipModule = [
@@ -1447,6 +1471,14 @@ in
nvimSkipModule = "ibl.config.types";
};
indent-tools-nvim = super.indent-tools-nvim.overrideAttrs {
dependencies = with self; [
arshlib-nvim
nvim-treesitter
nvim-treesitter-textobjects
];
};
instant-nvim = super.instant-nvim.overrideAttrs {
nvimSkipModule = [
# Requires global variable config
@@ -1533,13 +1565,6 @@ in
];
};
lean-nvim = super.lean-nvim.overrideAttrs {
dependencies = with self; [
nvim-lspconfig
plenary-nvim
];
};
LeaderF = super.LeaderF.overrideAttrs {
nativeBuildInputs = [ python3.pkgs.setuptools ];
buildInputs = [ python3 ];
@@ -1553,6 +1578,13 @@ in
stripDebugList = [ "autoload/leaderf/python" ];
};
lean-nvim = super.lean-nvim.overrideAttrs {
dependencies = with self; [
nvim-lspconfig
plenary-nvim
];
};
leap-ast-nvim = super.leap-ast-nvim.overrideAttrs {
dependencies = with self; [
leap-nvim
@@ -1663,12 +1695,6 @@ in
dependencies = [ self.nvim-lspconfig ];
};
lsp_extensions-nvim = super.lsp_extensions-nvim.overrideAttrs {
dependencies = [ self.plenary-nvim ];
};
lsp_lines-nvim = callPackage ./non-generated/lsp_lines-nvim { };
lspecho-nvim = super.lspecho-nvim.overrideAttrs {
meta.license = lib.licenses.mit;
};
@@ -1678,6 +1704,12 @@ in
nvimRequireCheck = "lspsaga";
};
lsp_extensions-nvim = super.lsp_extensions-nvim.overrideAttrs {
dependencies = [ self.plenary-nvim ];
};
lsp_lines-nvim = callPackage ./non-generated/lsp_lines-nvim { };
ltex_extra-nvim = super.ltex_extra-nvim.overrideAttrs {
# Other modules require setup call first
nvimRequireCheck = "ltex_extra";
@@ -1806,18 +1838,6 @@ in
'';
};
git-conflict-nvim = super.git-conflict-nvim.overrideAttrs {
# TODO: Remove after next fixed version
# https://github.com/akinsho/git-conflict.nvim/issues/103
version = "2.1.0";
src = fetchFromGitHub {
owner = "akinsho";
repo = "git-conflict.nvim";
tag = "v2.1.0";
hash = "sha256-1t0kKxTGLuOvuRkoLgkoqMZpF+oKo8+gMsTdgPsSb+8=";
};
};
minimap-vim = super.minimap-vim.overrideAttrs {
preFixup = ''
substituteInPlace $out/plugin/minimap.vim \
@@ -2229,11 +2249,11 @@ in
dependencies = [ self.plenary-nvim ];
};
notmuch-vim = notmuch.vim;
NotebookNavigator-nvim = super.NotebookNavigator-nvim.overrideAttrs {
};
notmuch-vim = notmuch.vim;
nterm-nvim = super.nterm-nvim.overrideAttrs {
dependencies = [ self.aniseed ];
};
@@ -2296,12 +2316,6 @@ in
dependencies = [ self.plenary-nvim ];
};
nvim-dap-cortex-debug = super.nvim-dap-cortex-debug.overrideAttrs {
dependencies = [ self.nvim-dap ];
};
nvim-dbee = callPackage ./non-generated/nvim-dbee { };
nvim-coverage = super.nvim-coverage.overrideAttrs {
dependencies = with self; [
neotest
@@ -2313,6 +2327,10 @@ in
];
};
nvim-dap-cortex-debug = super.nvim-dap-cortex-debug.overrideAttrs {
dependencies = [ self.nvim-dap ];
};
nvim-dap-lldb = super.nvim-dap-lldb.overrideAttrs {
dependencies = [ self.nvim-dap ];
};
@@ -2342,16 +2360,18 @@ in
dependencies = [ self.nvim-dap ];
};
nvim-dbee = callPackage ./non-generated/nvim-dbee { };
nvim-FeMaco-lua = super.nvim-FeMaco-lua.overrideAttrs {
dependencies = [ self.nvim-treesitter ];
};
nvim-fzf-commands = super.nvim-fzf-commands.overrideAttrs {
dependencies = [ self.nvim-fzf ];
# Requires global variable setup nvim_fzf_directory
nvimSkipModule = "fzf-commands.rg";
};
nvim-FeMaco-lua = super.nvim-FeMaco-lua.overrideAttrs {
dependencies = [ self.nvim-treesitter ];
};
nvim-genghis = super.nvim-genghis.overrideAttrs {
dependencies = [ self.dressing-nvim ];
@@ -2428,6 +2448,9 @@ in
nvim-navic
];
};
nvim-navic = super.nvim-navic.overrideAttrs {
dependencies = [ self.nvim-lspconfig ];
};
nvim-neoclip-lua = super.nvim-neoclip-lua.overrideAttrs {
nvimSkipModule = [
@@ -2442,6 +2465,11 @@ in
checkInputs = [ self.nvim-web-devicons ];
};
nvim-notify = super.nvim-notify.overrideAttrs {
# Optional fzf integration
nvimSkipModule = "notify.integrations.fzf";
};
nvim-nu = super.nvim-nu.overrideAttrs {
dependencies = with self; [
nvim-treesitter
@@ -2449,19 +2477,6 @@ in
];
};
vim-mediawiki-editor = super.vim-mediawiki-editor.overrideAttrs {
passthru.python3Dependencies = [ python3.pkgs.mwclient ];
};
nvim-navic = super.nvim-navic.overrideAttrs {
dependencies = [ self.nvim-lspconfig ];
};
nvim-notify = super.nvim-notify.overrideAttrs {
# Optional fzf integration
nvimSkipModule = "notify.integrations.fzf";
};
nvim-paredit = super.nvim-paredit.overrideAttrs {
dependencies = with self; [ nvim-treesitter ];
};
@@ -2497,6 +2512,29 @@ in
vimCommandCheck = "TealBuild";
};
nvim-test = super.nvim-test.overrideAttrs {
dependencies = with self; [
nvim-treesitter
nvim-treesitter-parsers.c_sharp
nvim-treesitter-parsers.go
nvim-treesitter-parsers.haskell
nvim-treesitter-parsers.javascript
nvim-treesitter-parsers.python
nvim-treesitter-parsers.ruby
nvim-treesitter-parsers.rust
nvim-treesitter-parsers.typescript
nvim-treesitter-parsers.zig
];
nvimSkipModule = [
# Optional toggleterm integration
"nvim-test.terms.toggleterm"
# Broken runners
"nvim-test.runners.zig"
"nvim-test.runners.hspec"
"nvim-test.runners.stack"
];
};
nvim-tree-lua = super.nvim-tree-lua.overrideAttrs {
nvimSkipModule = [
# Meta can't be required
@@ -2548,29 +2586,6 @@ in
dependencies = [ self.nvim-treesitter ];
};
nvim-test = super.nvim-test.overrideAttrs {
dependencies = with self; [
nvim-treesitter
nvim-treesitter-parsers.c_sharp
nvim-treesitter-parsers.go
nvim-treesitter-parsers.haskell
nvim-treesitter-parsers.javascript
nvim-treesitter-parsers.python
nvim-treesitter-parsers.ruby
nvim-treesitter-parsers.rust
nvim-treesitter-parsers.typescript
nvim-treesitter-parsers.zig
];
nvimSkipModule = [
# Optional toggleterm integration
"nvim-test.terms.toggleterm"
# Broken runners
"nvim-test.runners.zig"
"nvim-test.runners.hspec"
"nvim-test.runners.stack"
];
};
nvim-ufo = super.nvim-ufo.overrideAttrs {
dependencies = [ self.promise-async ];
};
@@ -2590,6 +2605,10 @@ in
dependencies = [ self.nvzone-volt ];
};
nvzone-typr = super.nvzone-typr.overrideAttrs {
dependencies = [ self.nvzone-volt ];
};
obsidian-nvim = super.obsidian-nvim.overrideAttrs {
checkInputs = with self; [
# Optional pickers
@@ -2615,10 +2634,6 @@ in
dependencies = [ self.plenary-nvim ];
};
onehalf = super.onehalf.overrideAttrs {
configurePhase = "cd vim";
};
omni-vim = super.omni-vim.overrideAttrs {
# Optional lightline integration
nvimSkipModule = "omni-lightline";
@@ -2634,6 +2649,10 @@ in
];
};
onehalf = super.onehalf.overrideAttrs {
configurePhase = "cd vim";
};
one-nvim = super.one-nvim.overrideAttrs {
# E5108: /lua/one-nvim.lua:14: Unknown option 't_Co'
# https://github.com/Th3Whit3Wolf/one-nvim/issues/23
@@ -2785,6 +2804,17 @@ in
];
};
quarto-nvim = super.quarto-nvim.overrideAttrs {
checkInputs = [
# Optional runner
self.iron-nvim
];
dependencies = with self; [
nvim-lspconfig
otter-nvim
];
};
quicker-nvim = super.quicker-nvim.overrideAttrs {
};
@@ -2802,12 +2832,6 @@ in
'';
};
aider-nvim = super.aider-nvim.overrideAttrs {
patches = [
(replaceVars ./patches/aider-nvim/bin.patch { aider = lib.getExe' aider-chat "aider"; })
];
};
refactoring-nvim = super.refactoring-nvim.overrideAttrs {
dependencies = with self; [
nvim-treesitter
@@ -2855,6 +2879,21 @@ in
];
};
rocks-nvim =
(neovimUtils.buildNeovimPlugin {
luaAttr = luaPackages.rocks-nvim;
}).overrideAttrs
(oa: {
passthru = oa.passthru // {
initLua = ''
vim.g.rocks_nvim = {
luarocks_binary = "${neovim-unwrapped.lua.pkgs.luarocks_bootstrap}/bin/luarocks"
}
'';
};
});
rustaceanvim = neovimUtils.buildNeovimPlugin {
checkInputs = [
# Optional integration
@@ -3090,16 +3129,16 @@ in
meta.maintainers = with lib.maintainers; [ callumio ];
};
taskwarrior3 = buildVimPlugin {
inherit (taskwarrior3) version pname;
src = "${taskwarrior3.src}/scripts/vim";
};
taskwarrior2 = buildVimPlugin {
inherit (taskwarrior2) version pname;
src = "${taskwarrior2.src}/scripts/vim";
};
taskwarrior3 = buildVimPlugin {
inherit (taskwarrior3) version pname;
src = "${taskwarrior3.src}/scripts/vim";
};
telekasten-nvim = super.telekasten-nvim.overrideAttrs {
dependencies = with self; [
plenary-nvim
@@ -3284,17 +3323,6 @@ in
dependencies = with self; [ telescope-nvim ];
};
quarto-nvim = super.quarto-nvim.overrideAttrs {
checkInputs = [
# Optional runner
self.iron-nvim
];
dependencies = with self; [
nvim-lspconfig
otter-nvim
];
};
telescope-zoxide = super.telescope-zoxide.overrideAttrs {
dependencies = with self; [ telescope-nvim ];
@@ -3344,6 +3372,11 @@ in
dependencies = [ self.plenary-nvim ];
};
trouble-nvim = super.trouble-nvim.overrideAttrs {
# Meta file
nvimSkipModule = "trouble.docs";
};
tsc-nvim = super.tsc-nvim.overrideAttrs {
patches = [ ./patches/tsc.nvim/fix-path.patch ];
@@ -3355,11 +3388,6 @@ in
nvimSkipModule = "tsc.better-messages-test";
};
trouble-nvim = super.trouble-nvim.overrideAttrs {
# Meta file
nvimSkipModule = "trouble.docs";
};
tssorter-nvim = super.tssorter-nvim.overrideAttrs {
dependencies = [ self.nvim-treesitter ];
};
@@ -3400,8 +3428,13 @@ in
];
};
nvzone-typr = super.nvzone-typr.overrideAttrs {
dependencies = [ self.nvzone-volt ];
typst-preview-nvim = super.typst-preview-nvim.overrideAttrs {
postPatch = ''
substituteInPlace lua/typst-preview/config.lua \
--replace-fail "['tinymist'] = nil," "tinymist = '${lib.getExe tinymist}'," \
--replace-fail "['websocat'] = nil," "websocat = '${lib.getExe websocat}',"
'';
};
unicode-vim =
@@ -3439,6 +3472,22 @@ in
};
};
vimacs = super.vimacs.overrideAttrs {
buildPhase = ''
substituteInPlace bin/vim \
--replace-fail '/usr/bin/vim' 'vim' \
--replace-fail '/usr/bin/gvim' 'gvim'
# remove unnecessary duplicated bin wrapper script
rm -r plugin/vimacs
'';
meta = with lib; {
description = "Vim-Improved eMACS: Emacs emulation plugin for Vim";
homepage = "http://algorithm.com.au/code/vimacs";
license = licenses.gpl2Plus;
maintainers = with lib.maintainers; [ millerjason ];
};
};
vimade = super.vimade.overrideAttrs {
checkInputs = with self; [
# Optional providers
@@ -3448,6 +3497,51 @@ in
];
};
# The GitHub repository returns 404, which breaks the update script
VimCompletesMe = buildVimPlugin {
pname = "VimCompletesMe";
version = "2022-02-18";
src = fetchFromGitHub {
owner = "ackyshake";
repo = "VimCompletesMe";
rev = "9adf692d7ae6424038458a89d4a411f0a27d1388";
sha256 = "1sndgb3291dyifaa8adri2mb8cgbinbar3nw1fnf67k9ahwycaz0";
};
meta.homepage = "https://github.com/ackyshake/VimCompletesMe/";
};
vim2nix = buildVimPlugin {
pname = "vim2nix";
version = "1.0";
src = ./vim2nix;
dependencies = [ self.vim-addon-manager ];
};
vimsence = super.vimsence.overrideAttrs {
meta = with lib; {
description = "Discord rich presence for Vim";
homepage = "https://github.com/hugolgst/vimsence";
maintainers = with lib.maintainers; [ hugolgst ];
};
};
vimproc-vim = super.vimproc-vim.overrideAttrs {
buildInputs = [ which ];
# TODO: revisit
buildPhase = ''
substituteInPlace autoload/vimproc.vim \
--replace-fail vimproc_mac.so vimproc_unix.so \
--replace-fail vimproc_linux64.so vimproc_unix.so \
--replace-fail vimproc_linux32.so vimproc_unix.so
make -f make_unix.mak
'';
};
vimshell-vim = super.vimshell-vim.overrideAttrs {
dependencies = [ self.vimproc-vim ];
};
vim-addon-actions = super.vim-addon-actions.overrideAttrs {
dependencies = with self; [
vim-addon-mw-utils
@@ -3678,6 +3772,10 @@ in
nvimSkipModule = "treesitter-matchup.third-party.query";
};
vim-mediawiki-editor = super.vim-mediawiki-editor.overrideAttrs {
passthru.python3Dependencies = [ python3.pkgs.mwclient ];
};
vim-metamath = super.vim-metamath.overrideAttrs {
preInstall = "cd vim";
};
@@ -3743,6 +3841,12 @@ in
nvimSkipModule = "tpipeline.main";
};
vim-ultest = super.vim-ultest.overrideAttrs {
# NOTE: vim-ultest is no longer maintained.
# If using Neovim, you can switch to using neotest (https://github.com/nvim-neotest/neotest) instead.
nvimSkipModule = "ultest";
};
vim-unimpaired = super.vim-unimpaired.overrideAttrs {
dependencies = [ self.vim-repeat ];
};
@@ -3773,73 +3877,6 @@ in
'';
};
vim2nix = buildVimPlugin {
pname = "vim2nix";
version = "1.0";
src = ./vim2nix;
dependencies = [ self.vim-addon-manager ];
};
vimacs = super.vimacs.overrideAttrs {
buildPhase = ''
substituteInPlace bin/vim \
--replace-fail '/usr/bin/vim' 'vim' \
--replace-fail '/usr/bin/gvim' 'gvim'
# remove unnecessary duplicated bin wrapper script
rm -r plugin/vimacs
'';
meta = with lib; {
description = "Vim-Improved eMACS: Emacs emulation plugin for Vim";
homepage = "http://algorithm.com.au/code/vimacs";
license = licenses.gpl2Plus;
maintainers = with lib.maintainers; [ millerjason ];
};
};
# The GitHub repository returns 404, which breaks the update script
VimCompletesMe = buildVimPlugin {
pname = "VimCompletesMe";
version = "2022-02-18";
src = fetchFromGitHub {
owner = "ackyshake";
repo = "VimCompletesMe";
rev = "9adf692d7ae6424038458a89d4a411f0a27d1388";
sha256 = "1sndgb3291dyifaa8adri2mb8cgbinbar3nw1fnf67k9ahwycaz0";
};
meta.homepage = "https://github.com/ackyshake/VimCompletesMe/";
};
vimsence = super.vimsence.overrideAttrs {
meta = with lib; {
description = "Discord rich presence for Vim";
homepage = "https://github.com/hugolgst/vimsence";
maintainers = with lib.maintainers; [ hugolgst ];
};
};
vimproc-vim = super.vimproc-vim.overrideAttrs {
buildInputs = [ which ];
# TODO: revisit
buildPhase = ''
substituteInPlace autoload/vimproc.vim \
--replace-fail vimproc_mac.so vimproc_unix.so \
--replace-fail vimproc_linux64.so vimproc_unix.so \
--replace-fail vimproc_linux32.so vimproc_unix.so
make -f make_unix.mak
'';
};
vimshell-vim = super.vimshell-vim.overrideAttrs {
dependencies = [ self.vimproc-vim ];
};
vim-ultest = super.vim-ultest.overrideAttrs {
# NOTE: vim-ultest is no longer maintained.
# If using Neovim, you can switch to using neotest (https://github.com/nvim-neotest/neotest) instead.
nvimSkipModule = "ultest";
};
vim-zettel = super.vim-zettel.overrideAttrs {
dependencies = with self; [
vimwiki
@@ -3987,28 +4024,4 @@ in
--replace-fail "'zoxide_executable', 'zoxide'" "'zoxide_executable', '${zoxide}/bin/zoxide'"
'';
};
typst-preview-nvim = super.typst-preview-nvim.overrideAttrs {
postPatch = ''
substituteInPlace lua/typst-preview/config.lua \
--replace-fail "['tinymist'] = nil," "tinymist = '${lib.getExe tinymist}'," \
--replace-fail "['websocat'] = nil," "websocat = '${lib.getExe websocat}',"
'';
};
rocks-nvim =
(neovimUtils.buildNeovimPlugin {
luaAttr = luaPackages.rocks-nvim;
}).overrideAttrs
(oa: {
passthru = oa.passthru // {
initLua = ''
vim.g.rocks_nvim = {
luarocks_binary = "${neovim-unwrapped.lua.pkgs.luarocks_bootstrap}/bin/luarocks"
}
'';
};
});
}
@@ -64,6 +64,7 @@ https://github.com/ckarnell/antonys-macro-repeater/,,
https://github.com/solarnz/arcanist.vim/,,
https://github.com/vim-scripts/argtextobj.vim/,,
https://github.com/otavioschwanck/arrow.nvim/,,
https://github.com/arsham/arshlib.nvim/,HEAD,
https://github.com/AstroNvim/astrocore/,HEAD,
https://github.com/AstroNvim/astrolsp/,HEAD,
https://github.com/AstroNvim/astrotheme/,,
@@ -469,6 +470,7 @@ https://github.com/haya14busa/incsearch-easymotion.vim/,,
https://github.com/haya14busa/incsearch.vim/,,
https://github.com/lukas-reineke/indent-blankline.nvim/,,
https://github.com/Darazaki/indent-o-matic/,,
https://github.com/arsham/indent-tools.nvim/,HEAD,
https://github.com/Yggdroot/indentLine/,,
https://github.com/ciaranm/inkpot/,,
https://github.com/jbyuki/instant.nvim/,HEAD,
@@ -7,8 +7,8 @@ vscode-utils.buildVscodeMarketplaceExtension {
mktplcRef = {
publisher = "RooVeterinaryInc";
name = "roo-cline";
version = "3.8.6";
hash = "sha256-t3QUqe0qYizrJQcsEmYYmNYS/cpYiHQXJHtzHk9MGS8=";
version = "3.9.2";
hash = "sha256-zRVppwnYpw03L+socmxAtLnkD72Ag7Wz9B4BbxpdFrk=";
};
meta = {
+2 -2
View File
@@ -8,13 +8,13 @@
python3Packages.buildPythonApplication rec {
pname = "eddy";
version = "3.6";
version = "3.7";
src = fetchFromGitHub {
owner = "obdasystems";
repo = pname;
tag = "v${version}";
sha256 = "sha256-vRmLUIqU0qfcnKzymBGb9gfM/uQiAcUHUnyz8iH/GrM=";
sha256 = "sha256-ywAxlXuKoTXfJSzSsvVXxhycVEklIPQfUogs8QJ8DGQ=";
};
propagatedBuildInputs = [
@@ -12,7 +12,8 @@ let
pname = "1password";
versions = builtins.fromJSON (builtins.readFile ./versions.json);
inherit (versions.${channel} or (throw "unknown channel ${channel}")) version;
hostOs = if stdenv.hostPlatform.isLinux then "linux" else "darwin";
version = versions."${channel}-${hostOs}" or (throw "unknown channel-os ${channel}-${hostOs}");
sources = builtins.fromJSON (builtins.readFile ./sources.json);
@@ -1,20 +1,20 @@
{
"stable": {
"x86_64-linux": {
"url": "https://downloads.1password.com/linux/tar/stable/x86_64/1password-8.10.60.x64.tar.gz",
"hash": "sha256-QCoV66LvGo6vA5fjuE3fG+LwehKVMPmgaDghh9YEvmA="
"url": "https://downloads.1password.com/linux/tar/stable/x86_64/1password-8.10.68.x64.tar.gz",
"hash": "sha256-6MekdtKnjvrP0dai6VfBEFJ+oKf2WvPp+sU/kVIzCTw="
},
"aarch64-linux": {
"url": "https://downloads.1password.com/linux/tar/stable/aarch64/1password-8.10.60.arm64.tar.gz",
"hash": "sha256-E5TniXur9ATJ3ER/zTFc6EiBrH/kbNvIao0ADLyBZZE="
"url": "https://downloads.1password.com/linux/tar/stable/aarch64/1password-8.10.68.arm64.tar.gz",
"hash": "sha256-2SpfkLu/4K1t2ILwOBMVAXeW7rbEzsjofn8naM1Szfc="
},
"x86_64-darwin": {
"url": "https://downloads.1password.com/mac/1Password-8.10.60-x86_64.zip",
"hash": "sha256-2Nv4CHKLgCFbU1TeJQhIq8YdkJSQJXtUw2S17B8cS4s="
"url": "https://downloads.1password.com/mac/1Password-8.10.68-x86_64.zip",
"hash": "sha256-t/glPvEGJH+IcYyrnW0fMSEeLB8mKqGqmZ8wnVFCJpo="
},
"aarch64-darwin": {
"url": "https://downloads.1password.com/mac/1Password-8.10.60-aarch64.zip",
"hash": "sha256-drJiM8EiUM3M54+KPQdLvAmSfBH5YPqQk14yjHzoBtM="
"url": "https://downloads.1password.com/mac/1Password-8.10.68-aarch64.zip",
"hash": "sha256-bhmuy8gUVCv+hYSIpYXgm8a0f1+JtyKb4g5cUIJCb28="
}
},
"beta": {
+12 -11
View File
@@ -30,8 +30,8 @@ mk_url() {
}
cleanup() {
if [[ -f ${GPG_KEYRING-} ]]; then
rm "${GPG_KEYRING}"
if [[ -d ${TMP_GNUPGHOME-} ]]; then
rm -r "${TMP_GNUPGHOME}"
fi
if [[ -f ${JSON_HEAP-} ]]; then
@@ -42,14 +42,14 @@ cleanup() {
trap cleanup EXIT
# Get channel versions from versions.json
declare -A version=(
["stable"]=$(jq -r '.stable.version' versions.json)
["beta"]=$(jq -r '.beta.version' versions.json)
)
declare -A versions
while IFS='=' read -r key value; do
versions["${key}"]="${value}"
done < <(jq -r 'to_entries[] | "\(.key)=\(.value)"' versions.json)
#
GPG_KEYRING=$(mktemp -t 1password.kbx.XXXXXX)
gpg --no-default-keyring --keyring "${GPG_KEYRING}" \
TMP_GNUPGHOME=$(mktemp -dt 1password-gui.gnupghome.XXXXXX)
export GNUPGHOME="${TMP_GNUPGHOME}"
gpg --no-default-keyring --keyring trustedkeys.kbx \
--keyserver keyserver.ubuntu.com \
--receive-keys 3FEF9748469ADBE15DA7CA80AC2D62742012EA22
@@ -57,7 +57,8 @@ JSON_HEAP=$(mktemp -t 1password-gui.jsonheap.XXXXXX)
for channel in stable beta; do
for os in linux darwin; do
for arch in x86_64 aarch64; do
url=$(mk_url ${os} ${channel} ${arch} "${version[${channel}]}")
version="${versions[${channel}-${os}]}"
url=$(mk_url ${os} ${channel} ${arch} ${version})
nix store prefetch-file --json "${url}" | jq "
{
\"${channel}\": {
@@ -71,7 +72,7 @@ for channel in stable beta; do
# For some reason 1Password PGP signs only Linux binaries.
if [[ ${os} == "linux" ]]; then
gpgv --keyring "${GPG_KEYRING}" \
gpgv \
$(nix store prefetch-file --json "${url}.sig" | jq -r .storePath) \
$(jq -r --slurp ".[-1].[].[].storePath" "${JSON_HEAP}")
fi
@@ -1,9 +1,6 @@
{
"stable": {
"version": "8.10.60"
},
"beta": {
"version": "8.10.68-12.BETA"
}
"stable-linux": "8.10.68",
"stable-darwin": "8.10.68",
"beta-linux":"8.10.68-12.BETA",
"beta-darwin": "8.10.68-12.BETA"
}
+2 -2
View File
@@ -9,13 +9,13 @@
mkDerivation rec {
pname = "heimer";
version = "4.4.0";
version = "4.5.0";
src = fetchFromGitHub {
owner = "juzzlin";
repo = pname;
rev = version;
hash = "sha256-47bQmT2bHcbWpeosuF/vpSJcws4SqTmalY/XFEf7cxQ=";
hash = "sha256-eKnGCYxC3b7qd/g2IMDyZveBg+jvFA9s3tWEGeTPSkU=";
};
nativeBuildInputs = [
@@ -5,16 +5,16 @@
}:
buildGoModule rec {
pname = "helm-dt";
version = "0.4.4";
version = "0.4.5";
src = fetchFromGitHub {
owner = "vmware-labs";
repo = "distribution-tooling-for-helm";
rev = "refs/tags/v${version}";
hash = "sha256-jSX18FJCQORHFIUBROWZqAO5EBPXFvN/k0NRfkdkUFM=";
hash = "sha256-/TRhi4YgEB5RwRZXuwGCCqHz3SoBfs1SdKLBWg1yed0=";
};
vendorHash = "sha256-8HefE1a3pcbBgq/bC0mnhWzSa5xTi2dbqw0tyJ9EyTI=";
vendorHash = "sha256-54QB8dZSqSpDb4z7di5K6d8/fFbXftKfQJAljV50/Jk=";
ldflags = [
"-s"
@@ -1,11 +1,11 @@
{
rke2Version = "1.31.5+rke2r1";
rke2Commit = "08e198bbe3f0b8d4c9b0af4d92085c06bb94aa89";
rke2TarballHash = "sha256-GG1GOs/kLWDCvc/+l0ymRpJzEthIyGpampCjvfnEPB8=";
rke2VendorHash = "sha256-xWqMidOWiLgJXp6AEITkyOieLw4yi1JMmi80YS4RNy0=";
k8sImageTag = "v1.31.5-rke2r1-build20250115";
etcdVersion = "v3.5.16-k3s1-build20241106";
rke2Version = "1.31.6+rke2r1";
rke2Commit = "f75cdf813703af4bc224b91bfb3c48d10aeb9fd0";
rke2TarballHash = "sha256-6HMF3EngR2S8LTpMq4b3B1ZUiBUJO8D3fhwaNMuAuPc=";
rke2VendorHash = "sha256-ug1dO4t/QfPpg3mobCIJWb8/MERUoP9tEMlKRKZigXo=";
k8sImageTag = "v1.31.6-rke2r1-build20250213";
etcdVersion = "v3.5.18-k3s1-build20250210";
pauseVersion = "3.6";
ccmVersion = "v1.31.2-0.20241016053446-0955fa330f90-build20241016";
dockerizedVersion = "v1.31.5-rke2r1";
dockerizedVersion = "v1.31.6-rke2r1";
}
@@ -866,6 +866,15 @@
"spdx": "MPL-2.0",
"vendorHash": "sha256-ZZtfVgxp7YXNRXpeUisLzweQhHzgYOuQDAp1MsxAVhg="
},
"nexus": {
"hash": "sha256-6RPga80ZoqEEFL7I2OVXcrwaxbdhSzZDEV07xL07rZs=",
"homepage": "https://registry.terraform.io/providers/datadrivers/nexus",
"owner": "datadrivers",
"repo": "terraform-provider-nexus",
"rev": "v2.5.0",
"spdx": "MPL-2.0",
"vendorHash": "sha256-wOpR+AJYW7YiARSIACta8Tr4bmGLUONRTEBLxHyHZZk="
},
"nomad": {
"hash": "sha256-k61iQ9FQG3nscBp5CE/fFCbHpeLawbUAtGPM+IZtfVc=",
"homepage": "https://registry.terraform.io/providers/hashicorp/nomad",
@@ -1066,11 +1075,11 @@
"vendorHash": "sha256-j+3qtGlueKZgf0LuNps4Wc9G3EmpSgl8ZNSLqslyizI="
},
"rancher2": {
"hash": "sha256-9I5awIsF/hQ4l4u518GoaUS+ik89mVPSkhHd9itE2eU=",
"hash": "sha256-LJgYGgJ7PLRq3WlT2rAnnM8svn4EGghLy3rY7lpmJxI=",
"homepage": "https://registry.terraform.io/providers/rancher/rancher2",
"owner": "rancher",
"repo": "terraform-provider-rancher2",
"rev": "v6.0.0",
"rev": "v6.1.4",
"spdx": "MPL-2.0",
"vendorHash": "sha256-uIyLOqabx8wQurxcG70LHm+jBga+bCNyf5XxGrt5OKA="
},
@@ -1300,11 +1309,11 @@
"vendorHash": "sha256-0B2XRpvUk0mgDu3inz37LLJijwH3aQyoSb8IaHr6was="
},
"tencentcloud": {
"hash": "sha256-UO3Gjz5+h4YIj62gCJccFWW8k7qNbmmBzFlT1WWdXl8=",
"hash": "sha256-vWMEaA64/h1dhXJDw2kqoWgpp79ZuWP25rvfd6GiReg=",
"homepage": "https://registry.terraform.io/providers/tencentcloudstack/tencentcloud",
"owner": "tencentcloudstack",
"repo": "terraform-provider-tencentcloud",
"rev": "v1.81.171",
"rev": "v1.81.174",
"spdx": "MPL-2.0",
"vendorHash": null
},
@@ -153,6 +153,10 @@ let
fixupPatches = dir: map (patch: replaceVars patch { inherit dir; });
in
{
z3_4_14 = common {
version = "4.14.1";
sha256 = "sha256-pTsDzf6Frk4mYAgF81wlR5Kb1x56joFggO5Fa3G2s70=";
};
z3_4_13 = common {
version = "4.13.4";
sha256 = "sha256-8hWXCr6IuNVKkOegEmWooo5jkdmln9nU7wI8T882BSE=";
@@ -2,25 +2,27 @@
lib,
python3,
fetchPypi,
fetchFromGitHub,
coreutils,
gitMinimal,
mercurial,
}:
python3.pkgs.buildPythonApplication rec {
version = "0.6.1";
version = "0.8.1";
pname = "nbstripout";
src = fetchPypi {
inherit pname version;
hash = "sha256-kGW83RSIs4bk88CB/8HUj0UTovjYv00NmiggjF2v6dM=";
hash = "sha256-6qyLa05yno3+Hl3ywPi6RKvFoXplRI8EgBQfgL4jC7E=";
};
# for some reason, darwin uses /bin/sh echo native instead of echo binary, so
# force using the echo binary
postPatch = ''
substituteInPlace tests/test-git.t --replace "echo" "${coreutils}/bin/echo"
'';
testAssets = fetchFromGitHub {
owner = "kynan";
repo = "nbstripout";
rev = "${version}";
hash = "sha256-OSJLrWkYQIhcdyofS3Bo39ppsU6K3A4546UKB8Q1GGg=";
};
propagatedBuildInputs = with python3.pkgs; [
nbformat
@@ -33,14 +35,21 @@ python3.pkgs.buildPythonApplication rec {
mercurial
]
++ (with python3.pkgs; [
pytest-cram
pytestCheckHook
]);
checkInputs = [
testAssets
];
preCheck = ''
export HOME=$(mktemp -d)
export PATH=$out/bin:$PATH
git config --global init.defaultBranch main
cp -r --no-preserve=mode,ownership ${testAssets}/tests/e2e_notebooks $TMPDIR/e2e_notebooks
chmod -R +w $TMPDIR/e2e_notebooks
substituteInPlace tests/test_end_to_end.py --replace "tests/e2e_notebooks" "$TMPDIR/e2e_notebooks"
'';
meta = {
@@ -21,19 +21,19 @@
rustPlatform.buildRustPackage {
pname = "crosvm";
version = "0-unstable-2025-02-18";
version = "0-unstable-2025-03-14";
src = fetchgit {
url = "https://chromium.googlesource.com/chromiumos/platform/crosvm";
rev = "10d2f33440475cb1a96eba1dc27c59c8b57b68bd";
hash = "sha256-FUTscDaqRgsabLcYq/fny3qXtBiwRRf8RVQBmDUyYrY=";
rev = "af765802907dafe1ae1d1f39704c5020a882d362";
hash = "sha256-p15gljpEaSloorT37J8Akn5DaqkjVD/QInik4FaF1HE=";
fetchSubmodules = true;
};
separateDebugInfo = true;
useFetchCargoVendor = true;
cargoHash = "sha256-hkDfqNoDn0TSvnQ2eVYEeB+f+JAnPI7BVcQBd9sjYzk=";
cargoHash = "sha256-3+gV/4l+N4U2zZWU+UtA1gcmdwnXavbhBPQOB3hhGDk=";
nativeBuildInputs = [
pkg-config
@@ -9,19 +9,19 @@ let
callPackage
(import ./generic.nix rec {
pname = "apptainer";
version = "1.3.6";
version = "1.4.0";
projectName = "apptainer";
src = fetchFromGitHub {
owner = "apptainer";
repo = "apptainer";
tag = "v${version}";
hash = "sha256-ZdSo9bKZ7Q1xwMe4SR840U3+fVpKwtiZQA5KDM5qF9M=";
hash = "sha256-whitdwFOvQgRS9lwbsWhhm92+i1qGW+OFOreNSyvldk=";
};
# Override vendorHash with overrideAttrs.
# See https://nixos.org/manual/nixpkgs/unstable/#buildGoModule-vendorHash
vendorHash = "sha256-W853++SSvkAYYUczbl8vnoBQZnimUdsAEXp4MCkLPBU=";
vendorHash = "sha256-HP5XJ74ELaZT/bZgAPqe7vBPvJhHwyZVSNrUa+KToIE=";
extraDescription = " (previously known as Singularity)";
extraMeta.homepage = "https://apptainer.org";
@@ -11,6 +11,7 @@
rootModules,
kmod,
allowMissing ? false,
extraFirmwarePaths ? [ ],
}:
stdenvNoCC.mkDerivation {
@@ -25,6 +26,7 @@ stdenvNoCC.mkDerivation {
firmware
rootModules
allowMissing
extraFirmwarePaths
;
allowedReferences = [ "out" ];
}
@@ -87,6 +87,15 @@ for module in $(< ~-/closure); do
done || :
done
for path in $extraFirmwarePaths; do
mkdir -p $(dirname $out/lib/firmware/$path)
for name in "$path" "$path.xz" "$path.zst" ""; do
if cp -v --parents --no-preserve=mode lib/firmware/$name "$out" 2>/dev/null; then
break
fi
done
done
if test -e lib/firmware/edid ; then
echo "lib/firmware/edid found, copying."
mkdir -p "$out/lib/firmware"
+3 -3
View File
@@ -2,17 +2,17 @@
rustPlatform.buildRustPackage rec {
pname = "ab-av1";
version = "0.9.1";
version = "0.9.3";
src = fetchFromGitHub {
owner = "alexheretic";
repo = "ab-av1";
rev = "v${version}";
hash = "sha256-I9XApll0/mvfhL/BLWoVwL0ffqa5r3dOBWYTHizJ0hc=";
hash = "sha256-rj02Opkwi4M249Ya4uBl4u1l8Mx+FBcRcxDgD6ng9kg=";
};
useFetchCargoVendor = true;
cargoHash = "sha256-y+5rW3LruV1WeJXizbhHs01jkWrYsMXZkn1NG0Xz3bg=";
cargoHash = "sha256-Vi38eNn+SnhQx7Gp1T2RPIBeu3bUAZ74dr0mMG5Mha0=";
nativeBuildInputs = [ installShellFiles ];
+2 -2
View File
@@ -6,11 +6,11 @@
stdenv.mkDerivation rec {
pname = "acpi";
version = "1.7";
version = "1.8";
src = fetchurl {
url = "mirror://sourceforge/acpiclient/${version}/${pname}-${version}.tar.gz";
sha256 = "01ahldvf0gc29dmbd5zi4rrnrw2i1ajnf30sx2vyaski3jv099fp";
sha256 = "sha256-5kxuALU815dCfqMqFgUTQlsD7U8HdzP3Hx8J/zQPIws=";
};
meta = with lib; {
+3 -3
View File
@@ -6,16 +6,16 @@
buildGoModule rec {
pname = "alterx";
version = "0.0.3";
version = "0.0.6";
src = fetchFromGitHub {
owner = "projectdiscovery";
repo = "alterx";
tag = "v${version}";
hash = "sha256-A01XROFB2NkArfFtRMv/r9Nu5QoKMTOVzVIUnFoVe78=";
hash = "sha256-IjCK0TVZOBegNdfpqOFoOTuj8KtmCuIqNPvcIa1vSo0=";
};
vendorHash = "sha256-efwU41kFR8QYa2cevvj4pYAXgCisJ4OHaRIhWVnETvc=";
vendorHash = "sha256-aTA5KGeYmJnbVRbEhT9LigQoJFLD17q9spzBV4BGhNw=";
meta = with lib; {
description = "Fast and customizable subdomain wordlist generator using DSL";
+16 -4
View File
@@ -2,32 +2,44 @@
lib,
python3,
fetchFromGitLab,
fetchPypi,
}:
let
tzdata = python3.pkgs.tzdata.overrideAttrs rec {
version = "2023.4";
src = fetchPypi {
pname = "tzdata";
inherit version;
hash = "sha256-3VTJTylHZVIsdzmWSbT+/ZVSJHmmZKDOyH9BvrxhSMk=";
};
};
in
python3.pkgs.buildPythonApplication rec {
pname = "annextimelog";
version = "0.13.1";
version = "0.14.0";
format = "pyproject";
src = fetchFromGitLab {
owner = "nobodyinperson";
repo = "annextimelog";
rev = "v${version}";
hash = "sha256-VgeILw8WfqVrmsU/kBw+jHTOt2a6sVT7YgP2pKRp2AY=";
hash = "sha256-+3PkG33qKckagSVvVdqkypulO7uu5AMOv8fQiP8IUbs=";
};
nativeBuildInputs = with python3.pkgs; [
setuptools
wheel
poetry-core
];
] ++ [ tzdata ];
propagatedBuildInputs = with python3.pkgs; [
rich
];
meta = with lib; {
description = "Git Annex-backed Time Tracking";
description = "git-annex based cli time tracker";
homepage = "https://gitlab.com/nobodyinperson/annextimelog";
license = licenses.gpl3Plus;
maintainers = with maintainers; [ matthiasbeyer ];
+2 -2
View File
@@ -23,13 +23,13 @@
}:
stdenv.mkDerivation (finalAttrs: {
pname = "aquamarine";
version = "0.7.2";
version = "0.8.0";
src = fetchFromGitHub {
owner = "hyprwm";
repo = "aquamarine";
rev = "v${finalAttrs.version}";
hash = "sha256-ldWD4ci3LcBIfUN41qlBO/oR5chcsRLejMbSW8eH628=";
hash = "sha256-ybpV2+yNExdHnMhhhmtxqgBCgI+nRr8gi/D+VVb9lQY=";
};
nativeBuildInputs = [
@@ -32,13 +32,13 @@ let
in
stdenv.mkDerivation (finalAttrs: {
pname = "ayatana-indicator-datetime";
version = "24.5.0";
version = "24.5.1";
src = fetchFromGitHub {
owner = "AyatanaIndicators";
repo = "ayatana-indicator-datetime";
tag = finalAttrs.version;
hash = "sha256-lY49v2uZ7BawQoN/hmN6pbetHlSGjMHbS6S8Wl1bDmQ=";
hash = "sha256-rbKAixFjXOMYzduABmoIXissQXAoehfbkNntdtRyAqA=";
};
postPatch = ''
+3 -3
View File
@@ -6,16 +6,16 @@
buildGoModule rec {
pname = "badger";
version = "4.5.2";
version = "4.6.0";
src = fetchFromGitHub {
owner = "dgraph-io";
repo = "badger";
rev = "v${version}";
hash = "sha256-kjMLJAEZN+WANgXsQT7XYLEsc+IL9QwBmaNeD3kyjGw=";
hash = "sha256-W3vPTLGI7YT7dFklJnOcpfYqQ9aBCsel9L6q4WNincY=";
};
vendorHash = "sha256-m4Bv8RhaUzqyzQ78/Ktr+wLRwL4mlXEsisW4pOJw1DI=";
vendorHash = "sha256-UVdOiaj1FN0etB9F0kt+THfO0Aa1kgdGYVeSVv4GpxY=";
subPackages = [ "badger" ];
+15 -10
View File
@@ -11,19 +11,24 @@
rustPlatform.buildRustPackage rec {
pname = "below";
version = "0.8.1";
version = "0.9.0";
src = fetchFromGitHub {
owner = "facebookincubator";
repo = "below";
rev = "v${version}";
sha256 = "sha256-87Fdx3Jqi3dNWM5DZl+UYs031qn2DoiiWd3IysT/glQ=";
tag = "v${version}";
hash = "sha256-tPweJFqhZMOL+M08bDjW6HPmtuhr9IXJNP0c938O7Cg=";
};
useFetchCargoVendor = true;
cargoHash = "sha256-iRDe3zg7tfEYGLCRY6bJ6OdoT8ej0MB/vteCIf5xqNA=";
# Upstream forgot to commit an up-to-date lockfile.
cargoPatches = [ ./update-Cargo.lock.patch ];
prePatch = ''sed -i "s,ExecStart=.*/bin,ExecStart=$out/bin," etc/below.service'';
useFetchCargoVendor = true;
cargoHash = "sha256-uNeWdsvJtkUz3E1NL10heDC7B55yKzDMMYzRhEE32EQ=";
prePatch = ''
sed -i "s,ExecStart=.*/bin,ExecStart=$out/bin," etc/below.service
'';
postInstall = ''
install -d $out/lib/systemd/system
install -t $out/lib/systemd/system etc/below.service
@@ -48,11 +53,11 @@ rustPlatform.buildRustPackage rec {
# needs /sys/fs/cgroup
doCheck = false;
meta = with lib; {
platforms = platforms.linux;
maintainers = with maintainers; [ globin ];
meta = {
platforms = lib.platforms.linux;
maintainers = with lib.maintainers; [ globin ];
description = "Time traveling resource monitor for modern Linux systems";
license = licenses.asl20;
license = lib.licenses.asl20;
homepage = "https://github.com/facebookincubator/below";
mainProgram = "below";
};
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
{
lib,
stdenv,
fetchFromGitHub,
rustPlatform,
pkg-config,
libudev-zero,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "bitbox-bridge";
version = "1.6.1";
src = fetchFromGitHub {
owner = "BitBoxSwiss";
repo = "bitbox-bridge";
tag = "v${finalAttrs.version}";
fetchSubmodules = true;
hash = "sha256-+pMXWXGHyyBx3N0kiro9NS0mPmSQzzBmp+pkoBLH7z0=";
};
useFetchCargoVendor = true;
cargoHash = "sha256-6vD0XjGH1PXjiRjgnHWSZSixXOc2Yecui8U5FAGefBU=";
postPatch = ''
rm .cargo/config.toml
'';
nativeBuildInputs = [
pkg-config
];
buildInputs = lib.optionals stdenv.hostPlatform.isLinux [
libudev-zero
];
meta = {
description = "A bridge service that connects web wallets like Rabby to BitBox02";
homepage = "https://github.com/BitBoxSwiss/bitbox-bridge";
downloadPage = "https://bitbox.swiss/download/";
changelog = "https://github.com/BitBoxSwiss/bitbox-bridge/blob/v${finalAttrs.version}/CHANGELOG.md";
license = lib.licenses.asl20;
maintainers = with lib.maintainers; [
izelnakri
tensor5
];
mainProgram = "bitbox-bridge";
platforms = lib.platforms.unix;
};
})
+6 -1
View File
@@ -51,7 +51,7 @@ buildNpmPackage rec {
npmFlags = [ "--legacy-peer-deps" ];
npmRebuildFlags = [
# FIXME one of the esbuild versions fails to download @esbuild/linux-x64
# we'll run npm rebuild manually later
"--ignore-scripts"
];
@@ -60,6 +60,11 @@ buildNpmPackage rec {
shopt -s globstar
rm -r node_modules/**/prebuilds
shopt -u globstar
# FIXME one of the esbuild versions fails to download @esbuild/linux-x64
rm -r node_modules/esbuild node_modules/vite/node_modules/esbuild
npm rebuild --verbose
'';
postBuild = ''
+4 -4
View File
@@ -11,7 +11,7 @@
stdenv.mkDerivation rec {
pname = "bloop";
version = "2.0.8";
version = "2.0.9";
platform =
if stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isx86_64 then
@@ -42,11 +42,11 @@ stdenv.mkDerivation rec {
url = "https://github.com/scalacenter/bloop/releases/download/v${version}/bloop-${platform}";
sha256 =
if stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isx86_64 then
"sha256-ItPt5qjfRgtPNg6a/Zlc0ASfdvGXMMKV7SqNEOQ9u28="
"sha256-mslCzvJ+z5VNQkVa9HXjw2bUBprMgs3bAy3RmEt8OlI="
else if stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isx86_64 then
"sha256-zUSDUwZY1id/WFuC87Wa4eB48X4rmXvVC1/b2v5bhw4="
"sha256-XdMPo9O7ADhInmGFIOHihl1z4yPKAyDjCH7m3tCtKNo="
else if stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64 then
"sha256-1wsGL1G8/+xMvYNwe7EOyqEuEKDKiwA7yyyjfbGgxJQ="
"sha256-sJM00f2KBI6fnVj3U/h/pYAFT7QjZkfJ7ubDfFlRJ0Q="
else
throw "unsupported platform";
};
+5 -5
View File
@@ -87,14 +87,14 @@ in
let
bolt = stdenv.mkDerivation (finalAttrs: {
pname = "bolt-launcher";
version = "0.9.0";
version = "0.14.0";
src = fetchFromGitHub {
owner = "AdamCake";
repo = "bolt";
rev = finalAttrs.version;
tag = finalAttrs.version;
fetchSubmodules = true;
hash = "sha256-LIlRDcUWbQwIhFjtqYF+oVpTOPZ7IT0vMgysEVyJ1k8=";
hash = "sha256-fNCi2Wu+oOL6p8IBm6bHZ/rcaFmqoKs2DnXQ+ZA9McE=";
};
nativeBuildInputs = [
@@ -154,8 +154,8 @@ let
desktopName = "Bolt Launcher";
genericName = finalAttrs.pname;
comment = "An alternative launcher for RuneScape";
exec = "${finalAttrs.pname}-${finalAttrs.version}";
icon = finalAttrs.pname;
exec = "bolt-launcher";
icon = "bolt-launcher";
categories = [ "Game" ];
})
];
+3 -3
View File
@@ -15,17 +15,17 @@
rustPlatform.buildRustPackage rec {
pname = "broot";
version = "1.44.7";
version = "1.45.0";
src = fetchFromGitHub {
owner = "Canop";
repo = "broot";
rev = "v${version}";
hash = "sha256-GaOPC1lIu48qFo99AQ99f49e8qH/TEQubpluptLc0jY=";
hash = "sha256-Hif+ynwOxiZBAiNdbaU5SpI9s0yNxtH0qXXMfGO21H0=";
};
useFetchCargoVendor = true;
cargoHash = "sha256-J7zc1aTH62nL96cSb9CiIk8uJdR7nk9EnERiAfMvqNM=";
cargoHash = "sha256-Cw0Bh8S04oUlbbn3O3+uBoHEgh82XIcGQSGqkZFOc78=";
nativeBuildInputs = [
installShellFiles
+3 -3
View File
@@ -8,19 +8,19 @@
buildGoModule rec {
pname = "carapace-bridge";
version = "1.2.3";
version = "1.2.4";
src = fetchFromGitHub {
owner = "carapace-sh";
repo = "carapace-bridge";
tag = "v${version}";
hash = "sha256-RMItv9HAPsxnb0NGlDjqY8Of4cxf8xU1c8ZE8Ajz0ao=";
hash = "sha256-/HjoE6yaawo1hCemnvtfK3wj4SBSW91D4oyuZ5qxV4M=";
};
# buildGoModule try to run `go mod vendor` instead of `go work vendor` on the
# workspace if proxyVendor is off
proxyVendor = true;
vendorHash = "sha256-R2sk5yqhF+5pVWxCnEx+EKTvNPzg32/JguLMu6R3ETM=";
vendorHash = "sha256-zfV5IcpwtK3n76jWs4ldMlpEqbyNmmXZWDj+fh66luw=";
postPatch = ''
substituteInPlace cmd/carapace-bridge/main.go \
+3 -3
View File
@@ -7,16 +7,16 @@
buildGoModule rec {
pname = "civo";
version = "1.1.97";
version = "1.1.98";
src = fetchFromGitHub {
owner = "civo";
repo = "cli";
rev = "v${version}";
hash = "sha256-0BIvKzG+ePN4VyXPj4VfCoZiq/pDZb9/7k/kTIa4Fqs=";
hash = "sha256-gxqVWnhlLYizoij6L9/ThM9T7K7++nGZwgFP3OzBqOY=";
};
vendorHash = "sha256-V1R5MQ3y8mcm8ffc2INKk6BTYUROEvr8lHBs6MvbpkQ=";
vendorHash = "sha256-LN6rzZXw7YoHMyPCujPiyjs8tG+nN2fxwQnEenohw1c=";
nativeBuildInputs = [ installShellFiles ];
+3 -3
View File
@@ -7,16 +7,16 @@
buildGoModule rec {
pname = "cloud-nuke";
version = "0.38.2";
version = "0.39.0";
src = fetchFromGitHub {
owner = "gruntwork-io";
repo = pname;
tag = "v${version}";
hash = "sha256-hQFuHEIxsvyCmP4DR9MsrWmPbo3BFU3k5nYNsQVNy/U=";
hash = "sha256-r9/5A1f6GSDgF5/GM4UKxoCYUsc5xsZpTwDGDUySDfQ=";
};
vendorHash = "sha256-ExZZHCGmU9r1DrJ3alN6Y39P6rfFymQSpK8b+ZD7h0s=";
vendorHash = "sha256-AiPy/lmqrNeDWM7/pXmzHCbSWZdqdXnZNATlyi6oAGc=";
nativeBuildInputs = [
makeBinaryWrapper
@@ -0,0 +1,53 @@
{
lib,
stdenv,
fetchFromGitHub,
fetchYarnDeps,
yarnConfigHook,
yarnInstallHook,
nodejs,
nix-update-script,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "cloudflare-cli";
version = "4.2.0";
src = fetchFromGitHub {
owner = "danielpigott";
repo = "cloudflare-cli";
tag = "v${finalAttrs.version}";
hash = "sha256-cT+cMekXhHKfFi+dH1dCA/YNBSyYePJIZBSkDMPZZ14=";
};
yarnOfflineCache = fetchYarnDeps {
yarnLock = finalAttrs.src + "/yarn.lock";
hash = "sha256-0SFXgaLQE/MkqC9id7DAiP422tEyTt2gpgpIdXViFBI=";
};
nativeBuildInputs = [
yarnConfigHook
yarnInstallHook
nodejs
];
doInstallCheck = true;
installCheckPhase = ''
runHook preInstallCheck
$out/bin/cfcli --help >/dev/null
runHook postInstallCheck
'';
passthru.updateScript = nix-update-script { };
meta = {
description = "CLI for interacting with Cloudflare";
homepage = "https://github.com/danielpigott/cloudflare-cli";
changelog = "https://github.com/danielpigott/cloudflare-cli/releases/tag/v${finalAttrs.version}";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ defelo ];
mainProgram = "cfcli";
};
})
+2 -2
View File
@@ -9,13 +9,13 @@
buildGoModule rec {
pname = "clusterctl";
version = "1.9.5";
version = "1.9.6";
src = fetchFromGitHub {
owner = "kubernetes-sigs";
repo = "cluster-api";
rev = "v${version}";
hash = "sha256-4n+7/4ZMD0VzlD4PzEWVDut+rt8/4Vz3gAgCDAj+SVs=";
hash = "sha256-XXtVGIpoR2JfkR7urfHuh6xKoIvsF42NV+4yjxb8nls=";
};
vendorHash = "sha256-SdLeME6EFraGUXE1zUdEfxTETUKLDmecYpWEg5DE4PQ=";
+4 -1
View File
@@ -113,7 +113,10 @@ python3Packages.buildPythonApplication rec {
homepage = "https://github.com/Ericsson/codechecker";
changelog = "https://github.com/Ericsson/codechecker/releases/tag/v${version}";
description = "Analyzer tooling, defect database and viewer extension for the Clang Static Analyzer and Clang Tidy";
license = licenses.asl20-llvm;
license = with licenses; [
asl20
llvm-exception
];
maintainers = with maintainers; [
zebreus
felixsinger
+4 -4
View File
@@ -43,7 +43,7 @@
# $ conda-shell
# $ conda install spyder
let
version = "25.1.1";
version = "25.1.1-2";
src =
let
@@ -57,10 +57,10 @@ let
};
in
fetchurl {
url = "https://repo.anaconda.com/miniconda/Miniconda3-py312_${version}-0-Linux-${arch}.sh";
url = "https://repo.anaconda.com/miniconda/Miniconda3-py312_${version}-Linux-${arch}.sh";
hash = selectSystem {
x86_64-linux = "sha256-gy3ielo1t5Y/DYNGarraPrE45RmFJV8ZDg3DUEJ6ndE=";
aarch64-linux = "sha256-rp0+qD35fnj9UcRS0Lx1AFoo1QTCLbbxAAgiKT+Ra1Q=";
x86_64-linux = "sha256-R2bYW199I1ziUOmY67WoqCEMvU8rD+pNIXez7Z6oeIQ=";
aarch64-linux = "sha256-bQW5+bfzJ7kHl6TPVtaMgVeLqy9jJXo+eotyyw8OS10=";
};
};
+3
View File
@@ -7,6 +7,7 @@
# passthru
conduit,
python3Packages,
nix-update-script,
mpiSupport ? false,
@@ -50,6 +51,8 @@ stdenv.mkDerivation (finalAttrs: {
passthru = {
tests = {
withMpi = conduit.override { mpiSupport = true; };
pythonModule = python3Packages.conduit;
pythonModuleWithMpi = python3Packages.conduit-mpi;
};
updateScript = nix-update-script { };
};
+3 -3
View File
@@ -10,17 +10,17 @@
}:
rustPlatform.buildRustPackage rec {
pname = "cook-cli";
version = "0.7.1";
version = "0.10.0";
src = fetchFromGitHub {
owner = "cooklang";
repo = "cookcli";
rev = "v${version}";
hash = "sha256-3gLVsk6GCxOG24Md7E9fk28Vnc4kVDdwyZUD/GtSwFE=";
hash = "sha256-1m2+etJG+33fPTxBF8qT/U9WiZGcSn9r0WlK5PDL6/Q=";
};
useFetchCargoVendor = true;
cargoHash = "sha256-EoTCKpH8G3SsXkhQVsr9aX4Cupm+fzPtXHpoM1knqss=";
cargoHash = "sha256-3tWVCP80a6odmi9C0klLbfO5UmdFczyUY8KQSaMIyw4=";
nativeBuildInputs = [
pkg-config
+3 -3
View File
@@ -8,17 +8,17 @@
rustPlatform.buildRustPackage rec {
pname = "ccat";
version = "003";
version = "004";
src = fetchFromGitHub {
owner = "DeeKahy";
repo = "CopyCat";
tag = version;
hash = "sha256-BNXWubJ6eRnuK7+0kE9yHQzjJci5miTSG3dwWE2XDwc=";
hash = "sha256-HLT88ghyT9AwvBTf7NrFkSPqMAh90GrBqZVXN5aaG3w=";
};
useFetchCargoVendor = true;
cargoHash = "sha256-2SI4h5RqzWKWnRmQ2t/eDAOK1ql7jlZKIgPlSiiB6Dg=";
cargoHash = "sha256-gjFVvP2h+HJdDdNVtqTT1E1s4ZYXfWuhtMBRJkWRcDw=";
buildInputs = lib.optionals (stdenv.hostPlatform.isDarwin) [
darwin.apple_sdk_11_0.frameworks.AppKit
+3 -3
View File
@@ -9,18 +9,18 @@
}:
let
commitHash = "9d021bf61a094a5eac6ae3084ceed2dda4700a73"; # matches tag release
commitHash = "d5bc935e4801a02fdbd953f8f0ae7989eaef50cf"; # matches tag release
shortCommitHash = builtins.substring 0 7 commitHash;
in
buildGoModule rec {
pname = "copywrite";
version = "0.21.0";
version = "0.22.0";
src = fetchFromGitHub {
owner = "hashicorp";
repo = "copywrite";
tag = "v${version}";
hash = "sha256-TGis7rreRen+vk3tUDehRkyas4xrBBxKlA70+VqoGWY=";
hash = "sha256-gPVlHgFlLxoAj4pkg3OxD4CGQaLdAL312/Zn/pJ+7fg=";
};
vendorHash = "sha256-Qxp6BwN/Y6Xb1BwFGT/T8WYsXGPgN27mzoTE0i6cS1Q=";
+55
View File
@@ -0,0 +1,55 @@
{
lib,
rustPlatform,
fetchFromGitHub,
yq,
pkg-config,
openssl,
versionCheckHook,
nix-update-script,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "countryfetch";
version = "0.1.9";
src = fetchFromGitHub {
owner = "nik-rev";
repo = "countryfetch";
tag = "v${finalAttrs.version}";
hash = "sha256-KdFgY54vXLmq6IZfJzZ1IeZ2eQuNJoCRZUV3rVuPpcY=";
};
postPatch = ''
tomlq -ti '.dependencies.openssl.features[] |= select(.!="vendored")' countryfetch/Cargo.toml
'';
useFetchCargoVendor = true;
cargoHash = "sha256-XJI9k/5hdak8p0/J/x9u6lqJu/DIbX93Wwm3LALkAAw=";
env.RUSTC_BOOTSTRAP = 1;
nativeBuildInputs = [
pkg-config
yq # for `tomlq`
];
buildInputs = [ openssl ];
cargoBuildFlags = [ "--package=countryfetch" ];
nativeInstallCheckInputs = [ versionCheckHook ];
versionCheckProgramArg = "--version";
doInstallCheck = true;
passthru.updateScript = nix-update-script { };
meta = {
description = "Command-line tool similar to Neofetch for obtaining information about your country";
homepage = "https://github.com/nik-rev/countryfetch";
changelog = "https://github.com/nik-rev/countryfetch/blob/v${finalAttrs.version}/CHANGELOG.md";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ defelo ];
mainProgram = "countryfetch";
};
})
+2 -2
View File
@@ -16,13 +16,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "crocoddyl";
version = "2.2.0";
version = "3.0.0";
src = fetchFromGitHub {
owner = "loco-3d";
repo = "crocoddyl";
rev = "v${finalAttrs.version}";
hash = "sha256-j3TL5TpIdTkTO32Fuu+LyiieiXoOMvShi/LbBL5YYzA=";
hash = "sha256-oWcclzzuswiR1SaQJd6GnMltJ2vgt7AgJPT0FJzD1Gs=";
};
outputs = [
+3 -3
View File
@@ -27,17 +27,17 @@ let
self = buildRustPackage' {
pname = "czkawka";
version = "8.0.0";
version = "9.0.0";
src = fetchFromGitHub {
owner = "qarmin";
repo = "czkawka";
tag = self.version;
hash = "sha256-Uxko2TRIjqQvd7n9C+P7oMUrm3YY5j7TVzvijEjDwOM=";
hash = "sha256-ePiHDfQ1QC3nff8uWE0ggiTuulBomuoZ3ta0redUYXY=";
};
useFetchCargoVendor = true;
cargoHash = "sha256-lYS/G3mHNqKcI6XRAtESzgBiUHnNfV0ct0W6E75a7J4=";
cargoHash = "sha256-Djvb5Hen6XPm6aJuwa6cGPojz9+kXXidysr3URDwDFM=";
nativeBuildInputs = [
gobject-introspection
+2 -2
View File
@@ -13,7 +13,7 @@ let
in
stdenv.mkDerivation (finalAttrs: {
inherit pname;
version = "24.3.3";
version = "25.1";
src =
let
@@ -21,7 +21,7 @@ stdenv.mkDerivation (finalAttrs: {
in
fetchurl {
url = "https://www.dbvis.com/product_download/dbvis-${finalAttrs.version}/media/dbvis_linux_${underscoreVersion}.tar.gz";
hash = "sha256-RDmakZJ7mjTzx4QaKwT6H25dDvQANbLhd2+f8EYbmDA=";
hash = "sha256-Se2d5S8nXKmNJ1UoYNGJyvHC20THShjzGh2T98NhFv4=";
};
strictDeps = true;
+2 -2
View File
@@ -6,13 +6,13 @@
buildGoModule rec {
pname = "ddns-go";
version = "6.9.0";
version = "6.9.1";
src = fetchFromGitHub {
owner = "jeessy2";
repo = pname;
rev = "v${version}";
hash = "sha256-eHJVd7PHUrswF1j4MrsUmle0vB8/CtH43p5ILZGljrs=";
hash = "sha256-QGvXUYeT01+P843gBX+IJWTyPg0cPI9jZWh3tAcmEqE=";
};
vendorHash = "sha256-5XrwVIaQ2dMizx3Pj0dmLkpYwypUVnfxLNxmNsVhVzY=";
+3 -3
View File
@@ -9,16 +9,16 @@
buildGoModule rec {
pname = "diffoci";
version = "0.1.5";
version = "0.1.6";
src = fetchFromGitHub {
owner = "reproducible-containers";
repo = "diffoci";
rev = "v${version}";
hash = "sha256-ZVWnfg5uWYuqsNd4X6t1gWBGMfdcirSp7QZZDhqAfaI=";
hash = "sha256-rCSLHlHUWS0wEnN8R2v1h+kQ7K62VQPfZmySHGSFZlQ=";
};
vendorHash = "sha256-qb4HvK4UbJbtP/ypeptV/MMbhOu5UZDaGartq/RGpDM=";
vendorHash = "sha256-udVigglpCgdYzJe9vdGZiQepZeOplQjqKB4Za8a+u6k=";
ldflags = [
"-s"
+3 -3
View File
@@ -20,11 +20,11 @@ let
in
stdenv.mkDerivation (finalAttrs: {
pname = "apache-druid";
version = "31.0.0";
version = "32.0.0";
src = fetchurl {
url = "mirror://apache/druid/${finalAttrs.version}/apache-druid-${finalAttrs.version}-bin.tar.gz";
hash = "sha256-xppAoKNS/qB8WVMwBPxxHbOy5uDGl3IxrCWV1T+YQkE=";
hash = "sha256-JeHmraWOQNjaVYyhYQesBrwLHAqnqsEG6it6quj3K3I=";
};
dontBuild = true;
@@ -57,7 +57,7 @@ stdenv.mkDerivation (finalAttrs: {
runHook preInstall
mkdir $out
mv * $out
${optionalString mysqlSupport "ln -s ${mysql_jdbc}/share/java/mysql-connector-java.jar $out/extensions/mysql-metadata-storage"}
${optionalString mysqlSupport "ln -s ${mysql_jdbc}/share/java/mysql-connector-j.jar $out/extensions/mysql-metadata-storage"}
${finalAttrs.loadExtensions}
${finalAttrs.loadJars}
runHook postInstall
+3 -3
View File
@@ -8,17 +8,17 @@
rustPlatform.buildRustPackage rec {
pname = "dumbpipe";
version = "0.25.0";
version = "0.26.0";
src = fetchFromGitHub {
owner = "n0-computer";
repo = "dumbpipe";
rev = "v${version}";
hash = "sha256-nYM/QAG57491NqTAkqF1p3DeuVKDPvh6MUqYP/gAWyc=";
hash = "sha256-xQHVEJ+EgsrboXbPg7pGXXMjyedSLooqkTt/yYZACSo=";
};
useFetchCargoVendor = true;
cargoHash = "sha256-lg/FmeCYL9WVvvEMnkQj1WaxFH+7rBBxgL9zfwSdaVE=";
cargoHash = "sha256-uuY0nh4VHzyM7+cbgyycr5I3IjE0OeQ0eg12qVXe4BQ=";
buildInputs = lib.optionals stdenv.hostPlatform.isDarwin (
with darwin.apple_sdk.frameworks;
+2 -2
View File
@@ -33,14 +33,14 @@
stdenv.mkDerivation (finalAttrs: {
pname = "dwarfs";
version = "0.10.2";
version = "0.11.0";
src = fetchFromGitHub {
owner = "mhx";
repo = "dwarfs";
tag = "v${finalAttrs.version}";
fetchSubmodules = true;
hash = "sha256-wQ+6jSf/RWAI7cSRMb1zG09kOiyMM5xiy8yS6tl1ybI=";
hash = "sha256-UOIHtyOGKG0WPwKS1z0agMTvI0RF5sapJ5GoJ7a8+Vs=";
};
cmakeFlags = [
+3 -3
View File
@@ -27,11 +27,11 @@ let
in
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "dynamodb-local";
version = "2.5.4";
version = "2.6.0";
src = fetchurl {
url = "https://d1ni2b6xgvw0s0.cloudfront.net/v2.x/dynamodb_local_2024-12-23.tar.gz";
hash = "sha256-YLFWH6YUFkLb062at1pjFclId/b0LmBVESWxHqimLJc=";
url = "https://d1ni2b6xgvw0s0.cloudfront.net/v2.x/dynamodb_local_2025-03-13.tar.gz";
hash = "sha256-mAXZX+L17+z9f3/sMq+O+zLcg7YKGKL72BhhTtS2xuw=";
};
sourceRoot = ".";
+4 -1
View File
@@ -44,6 +44,9 @@ llvmPackages.stdenv.mkDerivation rec {
description = "High-performance automatic differentiation of LLVM and MLIR";
maintainers = with lib.maintainers; [ kiranshila ];
platforms = lib.platforms.all;
license = lib.licenses.asl20-llvm;
license = with lib.licenses; [
asl20
llvm-exception
];
};
}
@@ -0,0 +1,16 @@
diff --git a/src/Etterna/Singletons/DownloadManager.cpp b/src/Etterna/Singletons/DownloadManager.cpp
index b42ccd30..3606107d 100644
--- a/src/Etterna/Singletons/DownloadManager.cpp
+++ b/src/Etterna/Singletons/DownloadManager.cpp
@@ -6265,7 +6265,10 @@ Download::Install()
{
Core::Platform::requestUserAttention();
Message* msg;
- if (!SongManager::InstallSmzip(m_TempFileName))
+
+ auto path = FILEMAN->ResolvePath(m_TempFileName);
+
+ if (!SongManager::InstallSmzip(path))
msg = new Message("DownloadFailed");
else
msg = new Message("PackDownloaded");
+109
View File
@@ -0,0 +1,109 @@
{
lib,
stdenv,
fetchFromGitHub,
makeDesktopItem,
copyDesktopItems,
# deps
cmake,
pkg-config,
openssl,
libGLU,
xorg,
alsa-lib,
libjack2,
libpulseaudio,
libogg,
sse2neon,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "etterna";
version = "0.74.3";
src = fetchFromGitHub {
owner = "etternagame";
repo = "etterna";
tag = "v${finalAttrs.version}";
hash = "sha256-zzCk6axISswfTAk7rRha5HFzIHQ0AjpAZyAWzH+Cn1s=";
};
patches = [ ./fix-download-manager.patch ];
nativeBuildInputs = [
cmake
pkg-config
copyDesktopItems
];
buildInputs = [
openssl
alsa-lib
libjack2
libpulseaudio
libGLU
libogg
sse2neon
xorg.libXinerama
xorg.libXrandr
xorg.libX11
xorg.libXext # Needed for DPMS
xorg.libXvMC
];
desktopItems = [
(makeDesktopItem {
name = "etterna";
desktopName = "Etterna";
genericName = "Rhythm and dance game";
icon = "etterna";
tryExec = "etterna";
exec = "etterna";
categories = [
"Application"
"Game"
"ArcadeGame"
];
comment = "A cross-platform rhythm video game.";
terminal = false;
})
];
installPhase = ''
runHook preInstall
mkdir -p $out/{bin,share/etterna}
mkdir -p $out/share/applications
# copy select necessary game files into virtual fs
cp -r /build/source/{Announcers,Assets,BGAnimations,BackgroundEffects,BackgroundTransitions,Data,GameTools,NoteSkins,Scripts,Themes} "$out/share/etterna"
# copy binary
cp /build/source/Etterna $out/bin/.etterna-unwrapped
# Install the Icon
install -Dm644 /build/source/Docs/images/etterna-logo-light.svg "$out/share/icons/hicolor/scalable/apps/etterna.svg"
# wacky insertion of wrapper directly into phase, so that $out is set
cat > $out/bin/etterna << EOF
#!${stdenv.shell}
export ETTERNA_ROOT_DIR="\$HOME/.local/share/etterna"
export ETTERNA_ADDITIONAL_ROOT_DIRS="$out/share/etterna"
echo "HOME: \$HOME"
echo "PWD: \$(pwd)"
echo "ETTERNA_ADDITIONAL_ROOT_DIRS: \$ETTERNA_ADDITIONAL_ROOT_DIRS"
exec $out/bin/.etterna-unwrapped "\$@"
EOF
chmod +x $out/bin/etterna
runHook postInstall
'';
cmakeFlags = [ "-D WITH_CRASHPAD=OFF" ];
meta = {
description = "Advanced cross-platform rhythm game focused on keyboard play";
homepage = "https://etternaonline.com";
changelog = "https://github.com/etternagame/etterna/release/tag/v${finalAttrs.version}";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ alikindsys ];
mainProgram = "etterna";
};
})
+3 -3
View File
@@ -8,14 +8,14 @@
python3.pkgs.buildPythonApplication rec {
pname = "exabgp";
version = "4.2.22";
version = "4.2.25";
format = "pyproject";
src = fetchFromGitHub {
owner = "Exa-Networks";
repo = "exabgp";
tag = version;
hash = "sha256-PrdCAmefKCBmbBFp04KiQGSsZZ4KNFk/ZtMedh9oow4=";
hash = "sha256-YBxRDcm4Qt44W3lBHDwdvZq2pXEujbqJDh24JbXthMg=";
};
nativeBuildInputs = with python3.pkgs; [
@@ -39,7 +39,7 @@ python3.pkgs.buildPythonApplication rec {
meta = with lib; {
description = "BGP swiss army knife of networking";
homepage = "https://github.com/Exa-Networks/exabgp";
changelog = "https://github.com/Exa-Networks/exabgp/blob/${src.rev}/CHANGELOG.rst";
changelog = "https://github.com/Exa-Networks/exabgp/blob/${src.tag}/CHANGELOG.rst";
license = licenses.bsd3;
maintainers = with maintainers; [
hexa

Some files were not shown because too many files have changed in this diff Show More