Merge branch 'staging-next' into staging

This commit is contained in:
Michael Daniels 2026-06-08 22:01:24 -04:00
commit 8197942b23
No known key found for this signature in database
158 changed files with 1328 additions and 2191 deletions

View file

@ -2,7 +2,7 @@ name: Teams
on:
schedule:
# Every Tuesday at 19:42 (randomly chosen)
# Every Monday at 19:42 (randomly chosen)
- cron: '42 19 * * 1'
workflow_dispatch:

View file

@ -2,10 +2,11 @@
"acme": {
"description": "Maintain ACME-related packages and modules.",
"id": 3806126,
"maintainers": {},
"maintainers": {
"emilazy": 18535642
},
"members": {
"arianvp": 628387,
"emilazy": 18535642,
"m1cr0man": 3044438
},
"name": "ACME"
@ -71,11 +72,10 @@
"description": "coordinates efforts towards bootstrappable builds (see https://bootstrappable.org/)",
"id": 9141350,
"maintainers": {
"philiptaron": 43863,
"zeuner": 2545850
},
"members": {
"philiptaron": 43863
},
"members": {},
"name": "bootstrapping"
},
"categorization": {
@ -176,6 +176,7 @@
"description": "Improve Darwin-support across Nixpkgs and help maintainers without access to Darwin hardware. Apply to join through https://github.com/NixOS/nixpkgs/issues/323144 to keep the process transparent.",
"id": 2385202,
"maintainers": {
"emilazy": 18535642,
"toonn": 1486805
},
"members": {
@ -205,7 +206,6 @@
"donn": 12652988,
"dwt": 57199,
"eclairevoyant": 848000,
"emilazy": 18535642,
"ethancedwards8": 60861925,
"fiddlerwoaroof": 808745,
"fulsomenko": 14945057,
@ -410,9 +410,7 @@
"jtojnar": 705123
},
"members": {
"bobby285271": 20080233,
"dasj19": 7589338,
"hedning": 71978
"bobby285271": 20080233
},
"name": "GNOME"
},
@ -556,11 +554,12 @@
"id": 9955829,
"maintainers": {
"RossComputerGuy": 19699320,
"alyssais": 2768870
"alyssais": 2768870,
"emilazy": 18535642
},
"members": {
"Ericson2314": 1055245,
"emilazy": 18535642,
"peterwaller-arm": 52030119,
"rrbutani": 7833358,
"sternenseemann": 3154475
},
@ -695,8 +694,7 @@
"description": "",
"id": 174820,
"maintainers": {
"Ericson2314": 1055245,
"tomberek": 178444
"Ericson2314": 1055245
},
"members": {
"Mic92": 96200,
@ -704,6 +702,7 @@
"edolstra": 1148549,
"lisanna-dettwyler": 72424138,
"lovesegfault": 7243783,
"tomberek": 178444,
"xokdvium": 145775305
},
"name": "Nix team"
@ -852,15 +851,15 @@
"description": "Team that is interested in reproducible builds",
"id": 7625643,
"maintainers": {
"raboof": 131856,
"zimbatm": 3248
"raboof": 131856
},
"members": {
"Artturin": 56650223,
"Atemu": 18599032,
"RaitoBezarius": 314564,
"davidak": 91113,
"mschwaig": 3856390
"mschwaig": 3856390,
"zimbatm": 3248
},
"name": "reproducible"
},
@ -964,13 +963,13 @@
"description": "Maintain the standard environment and its surrounding logic.",
"id": 11265412,
"maintainers": {
"RossComputerGuy": 19699320
"RossComputerGuy": 19699320,
"emilazy": 18535642,
"philiptaron": 43863
},
"members": {
"Artturin": 56650223,
"Ericson2314": 1055245,
"emilazy": 18535642,
"philiptaron": 43863,
"reckenrode": 7413633
},
"name": "stdenv"

View file

@ -6686,6 +6686,12 @@
githubId = 90097;
name = "Derek Collison";
};
DerGrumpf = {
email = "phil.keier@hotmail.com";
github = "DerGrumpf";
githubId = 17272572;
name = "Phil Keier";
};
DerGuteMoritz = {
email = "moritz@twoticketsplease.de";
github = "DerGuteMoritz";
@ -10681,12 +10687,6 @@
githubId = 2427959;
name = "Hector Jusforgues";
};
hedning = {
email = "torhedinbronner@gmail.com";
github = "hedning";
githubId = 71978;
name = "Tor Hedin Brønner";
};
heel = {
email = "parizhskiy@gmail.com";
github = "HeeL";

View file

@ -130,6 +130,8 @@
- [linkding](https://linkding.link/), a self-hosted bookmark manager designed to be minimal, fast, and easy to set up. Available as [services.linkding](#opt-services.linkding.enable).
- [gs1200-exporter](https://github.com/robinelfrink/gs1200-exporter), a Prometheus exporter for Zyxel GS1200 series switches. Available as [services.gs1200-exporter](#opt-services.gs1200-exporter.enable).
- [Tinyauth](https://tinyauth.app/), a simple authentication middleware for web apps, with OAuth and LDAP support. Available as [services.tinyauth](#opt-services.tinyauth.enable).
- [Strichliste](https://www.strichliste.org), a digital self-service tallysheet used in hackerspaces, clubs and offices. Available as [services.strichliste](#opt-services.strichliste.enable).

View file

@ -26,6 +26,8 @@
- `services.timesyncd.extraConfig` has been removed in favor of the structured [](#opt-services.timesyncd.settings.Time) option. Use `services.timesyncd.settings.Time` to set any `timesyncd.conf(5)` option directly. For example, replace `services.timesyncd.extraConfig = "PollIntervalMaxSec=180";` with `services.timesyncd.settings.Time.PollIntervalMaxSec = 180;`.
- `services.firezone.server.provision` has been removed due to it being unmaintanable. Remove all uses of provisioning and use the WebUI to configure firezone.
## Other Notable Changes {#sec-release-26.11-notable-changes}
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->

View file

@ -1033,6 +1033,7 @@
./services/monitoring/grafana-to-ntfy.nix
./services/monitoring/grafana.nix
./services/monitoring/graphite.nix
./services/monitoring/gs1200-exporter.nix
./services/monitoring/hdaps.nix
./services/monitoring/heapster.nix
./services/monitoring/incron.nix

View file

@ -125,6 +125,12 @@ in
};
users.groups.scanservjs = { };
systemd.tmpfiles.rules = [
"d ${cfg.stateDir}/data 0755 scanservjs scanservjs - -"
"d ${cfg.stateDir}/data/preview 0755 scanservjs scanservjs - -"
"L+ ${cfg.stateDir}/data/preview/default.jpg - - - - ${package}/lib/data/preview/default.jpg"
];
systemd.services.scanservjs = {
description = "scanservjs";
after = [ "network.target" ];

View file

@ -0,0 +1,95 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.gs1200-exporter;
in
{
meta.maintainers = with lib.maintainers; [ DerGrumpf ];
options.services.gs1200-exporter = {
enable = lib.mkEnableOption "gs1200-exporter";
address = lib.mkOption {
type = lib.types.str;
description = "IP address or hostname of the GS1200 switch.";
example = "192.168.1.3";
};
port = lib.mkOption {
type = lib.types.port;
default = 9934;
description = "Port on which to expose Prometheus metrics.";
};
passwordFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to a file containing the password to log in to the GS1200 web interface.
This is the recommended option as it avoids storing the password in the Nix store.
Compatible with sops-nix and agenix.
'';
example = "/run/secrets/gs1200-password";
};
debug = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable debug logging. Logs are accessible via journalctl -u gs1200-exporter.";
};
verbose = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable verbose logging. Logs are accessible via journalctl -u gs1200-exporter.";
};
json = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Output logs in JSON format. Logs are accessible via journalctl -u gs1200-exporter.";
};
};
config = lib.mkIf cfg.enable {
systemd.services.gs1200-exporter = {
description = "Prometheus exporter for Zyxel GS1200 switches";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
DynamicUser = true;
Restart = "always";
# Hardening
NoNewPrivileges = true;
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
CapabilityBoundingSet = "";
};
script =
let
args = lib.concatStringsSep " " (
[
"--address ${cfg.address}"
"--port ${toString cfg.port}"
]
++ lib.optional cfg.debug "--debug"
++ lib.optional cfg.verbose "--verbose"
++ lib.optional cfg.json "--json"
);
in
''
export GS1200_PASSWORD=$(cat ${cfg.passwordFile})
exec ${lib.getExe pkgs.gs1200-exporter} ${args}
'';
};
};
}

View file

@ -1,709 +0,0 @@
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"})
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()

View file

@ -9,12 +9,8 @@ let
attrNames
boolToString
concatLines
concatLists
concatMapAttrs
concatStringsSep
filterAttrs
filterAttrsRecursive
flip
forEach
getExe
isBool
@ -26,16 +22,11 @@ let
mkMerge
mkOption
mkPackageOption
optionalAttrs
optionalString
recursiveUpdate
subtractLists
toUpper
types
;
cfg = config.services.firezone.server;
jsonFormat = pkgs.formats.json { };
availableAuthAdapters = [
"email"
"openid_connect"
@ -47,28 +38,6 @@ let
"jumpcloud"
];
typePortRange =
types.coercedTo types.port
(x: {
from = x;
to = x;
})
(
types.submodule {
options = {
from = mkOption {
type = types.port;
description = "The start of the port range, inclusive.";
};
to = mkOption {
type = types.port;
description = "The end of the port range, inclusive.";
};
};
}
);
# All non-secret environment variables or the given component
collectEnvironment =
component:
@ -119,29 +88,6 @@ let
)
);
provisionStateJson =
let
# Convert clientSecretFile options into the real counterpart
augmentedAccounts = flip mapAttrs cfg.provision.accounts (
accountName: account:
account
// {
auth = flip mapAttrs account.auth (
authName: auth:
recursiveUpdate auth (
optionalAttrs (auth.adapter_config.clientSecretFile != null) {
adapter_config.client_secret = "{env:AUTH_CLIENT_SECRET_${toUpper accountName}_${toUpper authName}}";
}
)
);
}
);
in
jsonFormat.generate "provision-state.json" {
# Do not include any clientSecretFile attributes in the resulting json
accounts = filterAttrsRecursive (k: _: k != "clientSecretFile") augmentedAccounts;
};
commonServiceConfig = {
AmbientCapabilities = [ ];
CapabilityBoundingSet = [ ];
@ -222,6 +168,12 @@ let
};
in
{
imports = [
(lib.mkRemovedOptionModule [ "services" "firezone" "server" "provision" ] ''
Firezone provisioning support has been removed due to outsized maintenance efforts. See https://github.com/NixOS/nixpkgs/pull/529428.
'')
];
options.services.firezone.server = {
enable = mkEnableOption "all Firezone components";
enableLocalDB = mkEnableOption "a local postgresql database for Firezone";
@ -521,393 +473,9 @@ in
description = "A list of trusted proxies";
};
};
provision = {
enable = mkEnableOption "provisioning of the Firezone domain server";
accounts = mkOption {
type = types.attrsOf (
types.submodule {
freeformType = jsonFormat.type;
options = {
name = mkOption {
type = types.str;
description = "The account name";
example = "My Organization";
};
features =
let
mkFeatureOption =
name: default:
mkOption {
type = types.bool;
inherit default;
description = "Whether to enable the `${name}` feature for this account.";
};
in
{
policy_conditions = mkFeatureOption "policy_conditions" true;
multi_site_resources = mkFeatureOption "multi_site_resources" true;
traffic_filters = mkFeatureOption "traffic_filters" true;
self_hosted_relays = mkFeatureOption "self_hosted_relays" true;
idp_sync = mkFeatureOption "idp_sync" true;
rest_api = mkFeatureOption "rest_api" true;
internet_resource = mkFeatureOption "internet_resource" true;
};
actors = mkOption {
type = types.attrsOf (
types.submodule {
options = {
type = mkOption {
type = types.enum [
"account_admin_user"
"account_user"
"service_account"
"api_client"
];
description = "The account type";
};
name = mkOption {
type = types.str;
description = "The name of this actor";
};
email = mkOption {
type = types.str;
description = "The email address used to authenticate as this account";
};
};
}
);
default = { };
example = {
admin = {
type = "account_admin_user";
name = "Admin";
email = "admin@myorg.example.com";
};
};
description = ''
All actors (users) to provision. The attribute name will only
be used to track the actor and does not have any significance
for Firezone.
'';
};
auth = mkOption {
type = types.attrsOf (
types.submodule {
freeformType = jsonFormat.type;
options = {
name = mkOption {
type = types.str;
description = "The name of this authentication provider";
};
adapter = mkOption {
type = types.enum availableAuthAdapters;
description = "The auth adapter type";
};
adapter_config.clientSecretFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
A file containing a the client secret for an openid_connect adapter.
You only need to set this if this is an openid_connect provider.
'';
};
};
}
);
default = { };
example = {
myoidcprovider = {
adapter = "openid_connect";
adapter_config = {
client_id = "clientid";
clientSecretFile = "/run/secrets/oidc-client-secret";
response_type = "code";
scope = "openid email name";
discovery_document_uri = "https://auth.example.com/.well-known/openid-configuration";
};
};
};
description = ''
All authentication providers to provision. The attribute name
will only be used to track the provider and does not have any
significance for Firezone.
'';
};
resources = mkOption {
type = types.attrsOf (
types.submodule {
options = {
type = mkOption {
type = types.enum [
"dns"
"cidr"
"ip"
];
description = "The resource type";
};
name = mkOption {
type = types.str;
description = "The name of this resource";
};
address = mkOption {
type = types.str;
description = "The address of this resource. Depending on the resource type, this should be an ip, ip with cidr mask or a domain.";
};
addressDescription = mkOption {
type = types.nullOr types.str;
default = null;
description = "An optional description for resource address, usually a full link to the resource including a schema.";
};
gatewayGroups = mkOption {
type = types.nonEmptyListOf types.str;
description = "A list of gateway groups (sites) which can reach the resource and may be used to connect to it.";
};
filters = mkOption {
type = types.listOf (
types.submodule {
options = {
protocol = mkOption {
type = types.enum [
"icmp"
"tcp"
"udp"
];
description = "The protocol to allow";
};
ports = mkOption {
type = types.listOf typePortRange;
example = [
443
{
from = 8080;
to = 8100;
}
];
default = [ ];
apply =
xs: map (x: if x.from == x.to then toString x.from else "${toString x.from} - ${toString x.to}") xs;
description = "Either a single port or port range to allow. Both bounds are inclusive.";
};
};
}
);
default = [ ];
description = "A list of filter to restrict traffic. If no filters are given, all traffic is allowed.";
};
};
}
);
default = { };
example = {
vaultwarden = {
type = "dns";
name = "Vaultwarden";
address = "vault.example.com";
address_description = "https://vault.example.com";
gatewayGroups = [ "my-site" ];
filters = [
{ protocol = "icmp"; }
{
protocol = "tcp";
ports = [
80
443
];
}
];
};
};
description = ''
All resources to provision. The attribute name will only be used to
track the resource and does not have any significance for Firezone.
'';
};
policies = mkOption {
type = types.attrsOf (
types.submodule {
options = {
description = mkOption {
type = types.nullOr types.str;
description = "The description of this policy";
};
group = mkOption {
type = types.str;
description = "The group which should be allowed access to the given resource.";
};
resource = mkOption {
type = types.str;
description = "The resource to which access should be allowed.";
};
};
}
);
default = { };
example = {
access_vaultwarden = {
name = "Allow anyone to access vaultwarden";
group = "everyone";
resource = "vaultwarden";
};
};
description = ''
All policies to provision. The attribute name will only be used to
track the policy and does not have any significance for Firezone.
'';
};
groups = mkOption {
type = types.attrsOf (
types.submodule {
options = {
name = mkOption {
type = types.str;
description = "The name of this group";
};
members = mkOption {
type = types.listOf types.str;
default = [ ];
description = "The members of this group";
};
forceMembers = mkOption {
type = types.bool;
default = false;
description = "Ensure that only the given members are part of this group at every server start.";
};
};
}
);
default = { };
example = {
users = {
name = "Users";
};
};
description = ''
All groups to provision. The attribute name will only be used
to track the group and does not have any significance for
Firezone.
A group named `everyone` will automatically be managed by Firezone.
'';
};
relayGroups = mkOption {
type = types.attrsOf (
types.submodule {
options = {
name = mkOption {
type = types.str;
description = "The name of this relay group";
};
};
}
);
default = { };
example = {
my-relays = {
name = "My Relays";
};
};
description = ''
All relay groups to provision. The attribute name
will only be used to track the relay group and does not have any
significance for Firezone.
'';
};
gatewayGroups = mkOption {
type = types.attrsOf (
types.submodule {
options = {
name = mkOption {
type = types.str;
description = "The name of this gateway group";
};
};
}
);
default = { };
example = {
my-gateways = {
name = "My Gateways";
};
};
description = ''
All gateway groups (sites) to provision. The attribute name
will only be used to track the gateway group and does not have any
significance for Firezone.
'';
};
};
}
);
default = { };
example = {
main = {
name = "My Account / Organization";
metadata.stripe.billing_email = "org@myorg.example.com";
features.rest_api = false;
};
};
description = ''
All accounts to provision. The attribute name specified here will
become the account slug. By using `"{file:/path/to/file}"` as a
string value anywhere in these settings, the provisioning script will
replace that value with the content of the given file at runtime.
Please refer to the [Firezone source code](https://github.com/firezone/firezone/blob/main/elixir/apps/domain/lib/domain/accounts/account.ex)
for all available properties.
'';
};
};
};
config = mkMerge [
{
assertions = [
{
assertion = cfg.provision.enable -> cfg.domain.enable;
message = "Provisioning must be done on a machine running the firezone domain server";
}
]
++ concatLists (
flip mapAttrsToList cfg.provision.accounts (
accountName: accountCfg:
[
{
assertion = (builtins.match "^[[:lower:]_-]+$" accountName) != null;
message = "An account name must contain only lowercase characters and underscores, as it will be used as the URL slug for this account.";
}
]
++ flip mapAttrsToList accountCfg.auth (
authName: _: {
assertion = (builtins.match "^[[:alnum:]_-]+$" authName) != null;
message = "The authentication provider attribute key must contain only letters, numbers, underscores or dashes.";
}
)
)
);
}
# Enable all components if the main server is enabled
(mkIf cfg.enable {
services.firezone.server.domain.enable = true;
@ -1015,7 +583,7 @@ in
FEATURE_INTERNET_RESOURCE_ENABLED = mkDefault true;
FEATURE_TRAFFIC_FILTERS_ENABLED = mkDefault true;
FEATURE_SIGN_UP_ENABLED = mkDefault (!cfg.provision.enable);
FEATURE_SIGN_UP_ENABLED = mkDefault true;
WEB_EXTERNAL_URL = mkDefault cfg.web.externalUrl;
API_EXTERNAL_URL = mkDefault cfg.api.externalUrl;
@ -1066,19 +634,6 @@ in
OUTBOUND_EMAIL_SMTP_PASSWORD = cfg.smtp.passwordFile;
};
})
(mkIf cfg.provision.enable {
# Load client secrets from authentication providers
services.firezone.server.settingsSecret = flip concatMapAttrs cfg.provision.accounts (
accountName: accountCfg:
flip concatMapAttrs accountCfg.auth (
authName: authCfg:
optionalAttrs (authCfg.adapter_config.clientSecretFile != null) {
"AUTH_CLIENT_SECRET_${toUpper accountName}_${toUpper authName}" =
authCfg.adapter_config.clientSecretFile;
}
)
);
})
(mkIf (cfg.openClusterFirewall && cfg.domain.enable) {
networking.firewall.allowedTCPPorts = [
cfg.domain.settings.ERLANG_DISTRIBUTION_PORT
@ -1156,14 +711,6 @@ in
fi
count=$((count++))
done
''
+ optionalString cfg.provision.enable ''
# Wait for server to fully come up. Not ideal to use sleep, but at least it works.
sleep 1
${loadSecretEnvironment "domain"}
ln -sTf ${provisionStateJson} provision-state.json
${getExe cfg.domain.package} rpc 'Code.eval_file("${./provision.exs}")'
'';
environment = collectEnvironment "domain";

View file

@ -71,10 +71,12 @@ in
};
};
system.activationScripts.setup-cde = ''
mkdir -p /var/dt/{tmp,appconfig/appmanager}
chmod a+w+t /var/dt/{tmp,appconfig/appmanager}
'';
systemd.tmpfiles.settings."10-cde" = {
"/var/dt".d.mode = "0755";
"/var/dt/tmp".d.mode = "1777";
"/var/dt/appconfig".d.mode = "0755";
"/var/dt/appconfig/appmanager".d.mode = "1777";
};
services.xserver.desktopManager.session = [
{

View file

@ -697,6 +697,7 @@ in
grocy = runTest ./grocy.nix;
grow-partition = runTest ./grow-partition.nix;
grub = runTest ./grub.nix;
gs1200-exporter = runTest ./gs1200-exporter.nix;
guacamole-server = runTest ./guacamole-server.nix;
guix = handleTest ./guix { };
gvisor = runTest ./gvisor.nix;
@ -1491,6 +1492,7 @@ in
sane = runTest ./sane.nix;
sanoid = runTest ./sanoid.nix;
saunafs = runTest ./saunafs.nix;
scanservjs = runTest ./scanservjs.nix;
scaphandre = runTest ./scaphandre.nix;
schleuder = runTest ./schleuder.nix;
scion-freestanding-deployment = runTest ./scion/freestanding-deployment;

View file

@ -1,86 +0,0 @@
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)

View file

@ -84,89 +84,15 @@ in
passwordFile = pkgs.writeText "tmpmailpasswd" "verysecurepassword";
};
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@localhost.localdomain";
};
client = {
type = "service_account";
name = "A client";
email = "client@example.com";
};
};
# service accounts aren't members of 'Everyone' so we need to add a separate group
groups.main = {
name = "main";
members = [
"client"
"admin"
];
};
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 = "main";
resource = "res1";
};
policies.pol2 = {
description = "Allow anyone res2 access";
group = "main";
resource = "res2";
};
policies.pol3 = {
description = "Allow anyone res3 access";
group = "main";
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,
...
}:
{
@ -181,14 +107,11 @@ in
logLevel = "debug";
name = "test-relay";
apiUrl = "wss://${domain}/api/";
tokenFile = "/tmp/shared/relay_token.txt";
tokenFile = pkgs.writeText "token" "token";
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,
@ -300,11 +223,8 @@ in
logLevel = "debug";
name = "test-gateway";
apiUrl = "wss://${domain}/api/";
tokenFile = "/tmp/shared/gateway_token.txt";
tokenFile = pkgs.writeText "token" "token";
};
# Don't auto-start so we can wait until the token was provisioned
systemd.services.firezone-gateway.wantedBy = lib.mkForce [ ];
};
client =
@ -326,11 +246,8 @@ in
logLevel = "debug";
name = "test-client-somebody";
apiUrl = "wss://${domain}/api/";
tokenFile = "/tmp/shared/client_token.txt";
tokenFile = pkgs.writeText "token" "token";
};
# Don't auto-start so we can wait until the token was provisioned
systemd.services.firezone-headless-client.wantedBy = lib.mkForce [ ];
};
};
@ -344,43 +261,13 @@ in
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'")
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")
'';
}

View file

@ -0,0 +1,20 @@
{ lib, ... }:
{
name = "gs1200-exporter";
meta.maintainers = with lib.maintainers; [ DerGrumpf ];
nodes.machine = _: {
services.gs1200-exporter = {
enable = true;
address = "192.168.2.4";
passwordFile = "/run/secrets/gs1200-password";
};
systemd.tmpfiles.rules = [
"f /run/secrets/gs1200-password 0400 root root - testpassword"
];
};
testScript = ''
machine.wait_for_unit("gs1200-exporter.service")
machine.wait_for_open_port(9934)
machine.succeed("curl -f http://localhost:9934/metrics")
'';
}

View file

@ -0,0 +1,23 @@
let
port = 1234;
in
{
name = "scanservjs";
nodes.machine =
{ ... }:
{
services.scanservjs = {
enable = true;
settings.host = "0.0.0.0";
settings.port = port;
};
};
testScript = ''
machine.wait_for_unit("scanservjs.service")
machine.wait_until_succeeds(
"curl --silent --fail --show-error --location http://localhost:${toString port}"
)
'';
}

View file

@ -558,4 +558,25 @@ pkgs.lib.recurseIntoAttrs rec {
EOF
'';
};
nvim_require_check_rtp_no_duplicate = vimUtils.buildVimPlugin {
pname = "neovim-require-check-rtp-no-duplicate-test";
version = "0";
src = runCommandLocal "neovim-require-check-rtp-no-duplicate-src" { } ''
mkdir -p "$out/lua/require-check-rtp-dedup"
cat > "$out/lua/require-check-rtp-dedup/init.lua" <<'EOF'
local target = "lua/require-check-rtp-dedup/init.lua"
local matches = vim.api.nvim_get_runtime_file(target, true)
if #matches ~= 1 then
error(
("expected plugin on runtimepath exactly once, found %d:\n%s"):format(
#matches,
table.concat(matches, "\n")
)
)
end
return {}
EOF
'';
};
}

View file

@ -98,9 +98,9 @@ run_require_checks() {
if [ "$skip" = false ]; then
echo "Attempting to require module: $name"
if @nvimBinary@ -es --headless -n -u NONE -i NONE --clean -V1 \
--cmd "set rtp+=$out,${deps// /,}" \
--cmd "set rtp+=$out,${nativeCheckInputs// /,}" \
--cmd "set rtp+=$out,${checkInputs// /,}" \
--cmd "set rtp+=${deps// /,}" \
--cmd "set rtp+=${nativeCheckInputs// /,}" \
--cmd "set rtp+=${checkInputs// /,}" \
"${luaPathArgs[@]}" \
--cmd "set packpath^=$packPathDir" \
--cmd "packadd testPlugin" \

View file

@ -12,26 +12,26 @@ vscode-utils.buildVscodeMarketplaceExtension {
sources = {
"x86_64-linux" = {
arch = "linux-x64";
hash = "sha256-l1bwzuEi8sCBsdad2a5UDPN12QtlHhhgXBfsNxP5GwA=";
hash = "sha256-qXGdFXx8Vr9oVStBjaeWEsQjhQUbp9MnLUfJtyhgwkA=";
};
"x86_64-darwin" = {
arch = "darwin-x64";
hash = "sha256-31Sj5KlZnRKa0sR2J4A4CRuDF8fwXlzikukH+OX/GpU=";
hash = "sha256-Bd3ool5Ep8I5iiTMUHF48r/sf3F1dROx6Umns0pDGzE=";
};
"aarch64-linux" = {
arch = "linux-arm64";
hash = "sha256-7m9or/105/YIjhMlwMFLcN9tP9hj/4NU85Y3/5DDuDw=";
hash = "sha256-Jv2lrdvY0tthJM2fifUlCW/QBzEZAa8QDHj4o+a4KxY=";
};
"aarch64-darwin" = {
arch = "darwin-arm64";
hash = "sha256-q7mGGv/L9N7hwM0EIKF7d+lxcl0V00a6I/CK8j5E8SE=";
hash = "sha256-VooAoTyysIFH1AaidcoRs7fJpID0LbmWnLdivGZfdrM=";
};
};
in
{
name = "ruff";
publisher = "charliermarsh";
version = "2026.46.0";
version = "2026.48.0";
}
// sources.${stdenvNoCC.hostPlatform.system}
or (throw "Unsupported system ${stdenvNoCC.hostPlatform.system}");

View file

@ -1215,8 +1215,8 @@ let
mktplcRef = {
name = "flutter";
publisher = "dart-code";
version = "3.134.0";
hash = "sha256-wWANxBh9Tg3VkfbcrR0NgOIC8cpeZJCNfOevT7E4zKY=";
version = "3.136.0";
hash = "sha256-RK493qHjEK/k8oy/OIzO3bvNnFo+ZftQhZMIAmBCaJk=";
};
meta.license = lib.licenses.mit;
@ -1375,8 +1375,8 @@ let
mktplcRef = {
name = "competitive-programming-helper";
publisher = "DivyanshuAgrawal";
version = "2026.5.1779885478";
hash = "sha256-8RU6JWHeYOAxof2TXpeXlXSVD9+0e0E46X85A11l4Pk=";
version = "2026.6.1780508121";
hash = "sha256-4kb7Nk+gctECMQM/cko+q1Bta1EKPXPEqyCQLBMkbEo=";
};
meta = {
changelog = "https://marketplace.visualstudio.com/items/DivyanshuAgrawal.competitive-programming-helper/changelog";
@ -2324,8 +2324,8 @@ let
mktplcRef = {
name = "vscode-vibrancy-continued";
publisher = "illixion";
version = "1.1.77";
hash = "sha256-khxajorzIntF2YwKVd6aZ1+doEr2oN4OliBpc7TTB7o=";
version = "1.1.78";
hash = "sha256-w0i0Gmqj2atCtEYW+0XvZech37qQaTjkt8MJRdHamxs=";
};
meta = {
downloadPage = "https://marketplace.visualstudio.com/items?itemName=illixion.vscode-vibrancy-continued";
@ -3997,8 +3997,8 @@ let
mktplcRef = {
name = "wikitext";
publisher = "RoweWilsonFrederiskHolme";
version = "4.0.4";
hash = "sha256-IEnWoRQfWx4TbysSQlOxG0c8kiqtR4fOhaV1JxDkRCw=";
version = "4.0.5";
hash = "sha256-VyrcgS93B5Xd4s101lnTw9o27ffcvmxkShCKJ+6H+2w=";
};
meta = {
description = "Extension that helps users view and write MediaWiki's Wikitext files";

View file

@ -7,8 +7,8 @@ vscode-utils.buildVscodeMarketplaceExtension rec {
mktplcRef = {
name = "oracle-java";
publisher = "oracle";
version = "25.1.0";
hash = "sha256-HjDSlvG6khFJA/3ukjVCrPqbQiAKVhgP6KcCfC/jUrc=";
version = "26.0.0";
hash = "sha256-SfZMOiSuABXcYVi4CmxUUUIeAUmp6s45jjyy4HXoe24=";
};
meta = {

View file

@ -7,19 +7,19 @@
let
supported = {
x86_64-linux = {
hash = "sha256-HECflrFni3eWxMs+BpjWBhU3pqF5jjMIEjkp9ibx784=";
hash = "sha256-7uZZuEijg1Aca1h2NrBwFU9iFnfhG17waXxqVlAKzTA=";
arch = "linux-x64";
};
x86_64-darwin = {
hash = "sha256-dCkSOClWWq3DGU9psrinI5f5oC69K+AhdHdXwKIQsFw=";
hash = "sha256-NPh3Sxf2k/Nj4vt0SGsa5H6QOI1IBaL20g79Pl4/iPg=";
arch = "darwin-x64";
};
aarch64-linux = {
hash = "sha256-XNIx2ibOe1/1lo8RkYkAv+oBDYpqnmMcIjpoulbrr+w=";
hash = "sha256-tszcouaPUGTH1MpGJfU0RiLvBN7qIhH1vC3XiAmHFK8=";
arch = "linux-arm64";
};
aarch64-darwin = {
hash = "sha256-rXVuQN0SDmymQNncFZzyD4H+j6hxp1yoiaNXnbzrlo0=";
hash = "sha256-JV9pZqq48q00GM0cg3Wu00qrrkn2fczbHBVqnCM84lI=";
arch = "darwin-arm64";
};
};
@ -34,7 +34,7 @@ vscode-utils.buildVscodeMarketplaceExtension {
mktplcRef = base // {
name = "tombi";
publisher = "tombi-toml";
version = "1.1.1";
version = "1.1.2";
};
meta = {
description = "TOML Language Server";

View file

@ -11,13 +11,13 @@
}:
mkLibretroCore {
core = "pcsx2";
version = "0-unstable-2026-05-30";
version = "0-unstable-2026-06-01";
src = fetchFromGitHub {
owner = "libretro";
repo = "ps2";
rev = "a1b104679bcf6a6cf943f1e9daee0e98515944c2";
hash = "sha256-NmVjqct6DaYdeAt/aMoHg0t5rs1k8srZ9JW6H5bGw5Y=";
rev = "65e8afb9e9ca0a3f3af32d9b35d7d8537cd3cbc1";
hash = "sha256-H6lZLLO1+ir+vPchq3XGHKsepmYLbohQFvoA0+yiQo0=";
fetchSubmodules = true;
};

View file

@ -129,6 +129,7 @@ stdenv.mkDerivation (finalAttrs: {
libxslt # for xsltproc
gobject-introspection
perl
python
vala
# for docs
@ -222,6 +223,8 @@ stdenv.mkDerivation (finalAttrs: {
gexiv2
];
strictDeps = true;
mesonFlags = [
"-Dbug-report-url=https://github.com/NixOS/nixpkgs/issues/new"
"-Dicc-directory=/run/current-system/sw/share/color/icc"
@ -335,6 +338,8 @@ stdenv.mkDerivation (finalAttrs: {
gtk = gtk3;
};
__structuredAttrs = true;
meta = {
description = "GNU Image Manipulation Program";
homepage = "https://www.gimp.org/";

View file

@ -177,7 +177,7 @@ rec {
longDescription = "Gammastep" + lib.removePrefix "Redshift" redshift.meta.longDescription;
homepage = "https://gitlab.com/chinstrap/gammastep";
mainProgram = "gammastep";
maintainers = [ ] ++ redshift.meta.maintainers;
maintainers = with lib.maintainers; [ acidbong ] ++ redshift.meta.maintainers;
};
};
}

View file

@ -1319,11 +1319,11 @@
"vendorHash": "sha256-7ZoJg1HEVj5Nygr46lmBZeJDfZuU4F90yntrgkBVgGg="
},
"tencentcloudstack_tencentcloud": {
"hash": "sha256-hBKPD0hQ9kjypeG8Q8xLD2pKGnyWjKAKGnImYG9hsq8=",
"hash": "sha256-9TTN1DmIXxqIWWiPdFQLRZbJ1mXkibXAOKfF4rJTPBE=",
"homepage": "https://registry.terraform.io/providers/tencentcloudstack/tencentcloud",
"owner": "tencentcloudstack",
"repo": "terraform-provider-tencentcloud",
"rev": "v1.82.98",
"rev": "v1.82.101",
"spdx": "MPL-2.0",
"vendorHash": null
},

View file

@ -7,13 +7,13 @@
let
pname = "mendeley";
version = "2.144.0";
version = "2.145.0";
executableName = "${pname}-reference-manager";
src = fetchurl {
url = "https://static.mendeley.com/bin/desktop/mendeley-reference-manager-${version}-x86_64.AppImage";
hash = "sha256-27cUm1ChdzG9Qxo0ntUAVZMA685YFZ3nbsLkZfxR3pk=";
hash = "sha256-yuoNGAV6JuPfm5GagzD4R2ojBRpKo9aZ8K92jC63MQE=";
};
appimageContents = appimageTools.extractType2 {

View file

@ -84,7 +84,7 @@ let
# modsrc at all.
withModsrc = !enableKvm;
virtualboxGuestAdditionsIso = callPackage guest-additions-iso/default.nix {
virtualboxGuestAdditionsIso = callPackage ./guest-additions-iso {
inherit virtualboxVersion;
};

View file

@ -46,12 +46,12 @@ in
stdenv.mkDerivation (finalAttrs: {
pname = binName;
version = "0.26.6";
version = "0.26.7";
src = fetchFromGitHub {
owner = "toeverything";
repo = "AFFiNE";
tag = "v${finalAttrs.version}";
hash = "sha256-aJeW8I7hx9VN5AU6gVq18cKO0QuKtc7JGUDbVsSXXE4=";
hash = "sha256-gtdhWLNZRNY91j9wVVny1bRAjZAwIvNJr11ePQapWYQ=";
};
patches = [

View file

@ -14,7 +14,7 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "agate";
version = "3.3.22";
version = "3.3.23";
__darwinAllowLocalNetworking = true;
@ -22,10 +22,10 @@ rustPlatform.buildRustPackage (finalAttrs: {
owner = "mbrubeck";
repo = "agate";
tag = "v${finalAttrs.version}";
hash = "sha256-TDBCIioVeuQz4Dj7Pf5VG+tLLokGjhgv5e6z1spr3vk=";
hash = "sha256-6xF1iCAW4tCSoVU0rBSSfREIqPdOPF8Z1+ScMyEX4SQ=";
};
cargoHash = "sha256-dNbtNQlbUZuZNcyydkRtzC0/Md1HrM3SDbA33exafiI=";
cargoHash = "sha256-K6BUKaVULb/x3b9UQ/wJPI/kjBIOUdLnB63FyMJEXDE=";
nativeBuildInputs = [ pkg-config ];
buildInputs = [ openssl ];

View file

@ -8,11 +8,11 @@
stdenv.mkDerivation (finalAttrs: {
pname = "allure";
version = "2.42.0";
version = "2.42.1";
src = fetchurl {
url = "https://github.com/allure-framework/allure2/releases/download/${finalAttrs.version}/allure-${finalAttrs.version}.tgz";
hash = "sha256-cpEtOo/fIH9RTvVbvu4gD2idIZ5PG7S7SaOmeQ7QTf4=";
hash = "sha256-+Pc79LvSz1uO7lHSdIeu9VydLyZQ2xEaUvqBCIZrqGw=";
};
dontConfigure = true;

View file

@ -7,11 +7,11 @@
let
pname = "altair";
version = "8.5.0";
version = "8.5.3";
src = fetchurl {
url = "https://github.com/altair-graphql/altair/releases/download/v${version}/altair_${version}_x86_64_linux.AppImage";
sha256 = "sha256-ImcnV+Z1J+6wGs3HmlCpXmLb/BbyEcunY+IZ2cbD8Ns=";
sha256 = "sha256-XPw4NCtkInCes471as0Vtvr/SMRaJS6MNBGg0oo/Dro=";
};
appimageContents = appimageTools.extract { inherit pname version src; };

View file

@ -7,13 +7,13 @@
stdenvNoCC.mkDerivation {
pname = "ananicy-rules-cachyos";
version = "0-unstable-2026-05-28";
version = "0-unstable-2026-06-03";
src = fetchFromGitHub {
owner = "CachyOS";
repo = "ananicy-rules";
rev = "b556fc67b4a648000d0b11092115dd83a3023254";
hash = "sha256-cNOY3yqZKYwPkz3EiybuW3e8AomO/pD+SJVFHhUGoSI=";
rev = "422e807d3376dc9d07e7acfa82b62b5d62275486";
hash = "sha256-wDlAbb9O0I7WXsvQ+xLBPRt+haKJjvCJR56TGRC9auA=";
};
dontConfigure = true;

View file

@ -1,58 +1,50 @@
{
lib,
stdenv,
fetchzip,
stdenvNoCC,
fetchurl,
autoPatchelfHook,
versionCheckHook,
}:
let
# Version and platform-specific data retrieved from Google's manifests
version = "1.0.6";
wholeVersion = "1.0.7-5858071034068992"; # unfortunately this has dumb versioning
version = builtins.head (lib.splitString "-" wholeVersion);
throwSystem = throw "Unsupported system: ${stdenvNoCC.hostPlatform.system}";
sourceData = {
"x86_64-linux" = {
url = "https://storage.googleapis.com/antigravity-public/antigravity-cli/1.0.6-5359777384103936/linux-x64/cli_linux_x64.tar.gz";
hash = "sha256-rxDLuuium+yQl3SiRcFhLzC5+ZCZU/tG2LQfFZMOYx4=";
x86_64-linux = fetchurl {
url = "https://storage.googleapis.com/antigravity-public/antigravity-cli/${wholeVersion}/linux-x64/cli_linux_x64.tar.gz";
hash = "sha256-8kaHmc0XPAPuATHb4rrkMhUzBqaLqi7n1UQPFcRB4Go=";
};
"aarch64-linux" = {
url = "https://storage.googleapis.com/antigravity-public/antigravity-cli/1.0.6-5359777384103936/linux-arm/cli_linux_arm64.tar.gz";
hash = "sha256-Mol5V3Lt2A89yrGdwWiOdv4y5dCZkMaT8onXG6IsQtc=";
aarch64-linux = fetchurl {
url = "https://storage.googleapis.com/antigravity-public/antigravity-cli/${wholeVersion}/linux-arm/cli_linux_arm64.tar.gz";
hash = "sha256-3ylG6ZW/9AuKydzzyMLtqC1ec2NnixFG/CJih26S0K0=";
};
"aarch64-darwin" = {
url = "https://storage.googleapis.com/antigravity-public/antigravity-cli/1.0.6-5359777384103936/darwin-arm/cli_mac_arm64.tar.gz";
hash = "sha256-GmAxVP6KW0Zii2kSDvwwzsa88r/4ko2BVVpS8BeING4=";
aarch64-darwin = fetchurl {
url = "https://storage.googleapis.com/antigravity-public/antigravity-cli/${wholeVersion}/darwin-arm/cli_mac_arm64.tar.gz";
hash = "sha256-e4VhL/9rUNgE2XyW8REz8QXEbzwsUFg41xNpUHfNLK0=";
};
"x86_64-darwin" = {
url = "https://storage.googleapis.com/antigravity-public/antigravity-cli/1.0.6-5359777384103936/darwin-x64/cli_mac_x64.tar.gz";
hash = "sha256-RqjKhRqiW6Fg61eYzem+uXb5LXBYi5Cyv0hwtCaqomo=";
x86_64-darwin = fetchurl {
url = "https://storage.googleapis.com/antigravity-public/antigravity-cli/${wholeVersion}/darwin-x64/cli_mac_x64.tar.gz";
hash = "sha256-SECE7bAd0VneVeAvBs14Ortkcqg8CJy9xcq3ZnuqfKY=";
};
};
sources = lib.mapAttrs (
_system: source:
fetchzip {
inherit (source) url hash;
}
) sourceData;
source =
sources.${stdenv.hostPlatform.system}
or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
in
stdenv.mkDerivation (finalAttrs: {
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "antigravity-cli";
inherit version;
src = source;
strictDeps = true;
__structuredAttrs = true;
nativeBuildInputs = lib.optionals stdenv.isLinux [ autoPatchelfHook ];
src = sourceData.${stdenvNoCC.hostPlatform.system} or throwSystem;
sourceRoot = ".";
nativeBuildInputs = lib.optionals stdenvNoCC.hostPlatform.isLinux [ autoPatchelfHook ];
dontBuild = true;
dontConfigure = true;
dontBuild = true;
installPhase = ''
runHook preInstall
@ -66,15 +58,8 @@ stdenv.mkDerivation (finalAttrs: {
doInstallCheck = true;
passthru = {
inherit sources;
updateScript = [
./update.sh
version
]
++ lib.concatMap (system: [
system
sourceData.${system}.url
]) (lib.attrNames sourceData);
inherit wholeVersion; # for the updateScript
updateScript = ./update.sh;
};
meta = {

View file

@ -1,60 +1,29 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p bash common-updater-scripts coreutils curl gnutar nix
# shellcheck shell=bash
#!nix-shell -i bash -p bash nix-update common-updater-scripts nix jq
set -euo pipefail
script_dir="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
nixpkgs_root="$(realpath "$script_dir/../../../..")"
package_file="$script_dir/package.nix"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
baseUrl=https://storage.googleapis.com/antigravity-public/antigravity-cli
cd -- "$nixpkgs_root"
currentVersion=$(nix-instantiate --eval --raw -E "with import ./. {}; antigravity-cli.version or (lib.getVersion antigravity-cli)")
latestVersion=$(curl $baseUrl/latest)
if (( $# < 3 || ($# - 1) % 2 != 0 )); then
echo "Usage: $0 <version> [<system> <url>]..." >&2
exit 1
if [[ "$currentVersion" == "$latestVersion" ]]; then
echo "package is up-to-date: $currentVersion"
exit 0
fi
version="$1"
shift
# urls unfortunately include a weird buildid that make it hard to get
latestWholeVersion=$(curl $baseUrl/$latestVersion/manifest.json | jq -r '.platforms."linux-x64".url' | cut -d/ -f6)
export NIXPKGS_ALLOW_UNFREE=1
update-source-version --version-key=wholeVersion antigravity-cli $latestWholeVersion || true
hash_url() {
local system="$1"
local url="$2"
local archive="$tmpdir/$system.tar.gz"
local unpack_dir="$tmpdir/$system-unpack"
mkdir -p "$unpack_dir"
curl -fsSL "$url" -o "$archive" || return
tar -xzf "$archive" -C "$unpack_dir" || return
if [[ ! -x "$unpack_dir/antigravity" ]]; then
echo "Expected executable 'antigravity' in $url" >&2
exit 1
fi
nix hash path --type sha256 "$unpack_dir"
}
while (( $# > 0 )); do
system="$1"
url="$2"
shift 2
if [[ "$url" != *"/antigravity-cli/$version-"* ]]; then
echo "URL for $system does not match package version $version: $url" >&2
exit 1
fi
echo "Hashing $system from $url"
hash="$(hash_url "$system" "$url")"
update-source-version antigravity-cli "$version" "$hash" \
--file="$package_file" \
--ignore-same-hash \
--ignore-same-version \
--source-key="sources.$system" \
--system="$system"
for system in \
x86_64-linux \
aarch64-linux \
x86_64-darwin \
aarch64-darwin; do
hash=$(nix store prefetch-file --json --hash-type sha256 \
$(nix-instantiate --eval --raw -E "with import ./. {}; antigravity-cli.src.url" --system "$system") | jq -r '.hash')
update-source-version --version-key=wholeVersion antigravity-cli $latestWholeVersion $hash --system=$system --ignore-same-version
done

View file

@ -11,13 +11,13 @@
buildGoModule (finalAttrs: {
pname = "apko";
version = "1.2.15";
version = "1.2.16";
src = fetchFromGitHub {
owner = "chainguard-dev";
repo = "apko";
tag = "v${finalAttrs.version}";
hash = "sha256-/Y5JqCCqbP+5Of4K6+Bdag9lLKiY/SJiz6x3W6gQnDE=";
hash = "sha256-RsUoolJ2WOs3wpQilAs6RfpR3YzOhzTvDaxuweErIKs=";
# populate values that require us to use git. By doing this in postFetch we
# can delete .git afterwards and maintain better reproducibility of the src.
leaveDotGit = true;

View file

@ -24,10 +24,13 @@
pkg-config,
pngquant,
}:
stdenv.mkDerivation rec {
stdenv.mkDerivation (finalAttrs: {
pname = "appstream-glib";
version = "0.8.3";
strictDeps = true;
__structuredAttrs = true;
outputs = [
"out"
"dev"
@ -39,7 +42,7 @@ stdenv.mkDerivation rec {
src = fetchFromGitHub {
owner = "hughsie";
repo = "appstream-glib";
tag = "appstream_glib_${lib.replaceStrings [ "." ] [ "_" ] version}";
tag = "appstream_glib_${lib.replaceStrings [ "." ] [ "_" ] finalAttrs.version}";
hash = "sha256-GjXrYV+EBduhG88LaxQWICKuUDJeeotcZgqgaG0/dqo=";
};
@ -91,11 +94,11 @@ stdenv.mkDerivation rec {
'';
meta = {
changelog = "https://github.com/hughsie/appstream-glib/blob/${src.tag}/NEWS";
changelog = "https://github.com/hughsie/appstream-glib/blob/${finalAttrs.src.tag}/NEWS";
description = "Objects and helper methods to read and write AppStream metadata";
homepage = "https://people.freedesktop.org/~hughsient/appstream-glib/";
license = lib.licenses.lgpl2Plus;
platforms = lib.platforms.unix;
maintainers = [ ];
};
}
})

View file

@ -11,19 +11,20 @@
wayland,
udev,
vulkan-loader,
nix-update-script,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "ashell";
version = "0.8.0";
version = "0.9.0";
src = fetchFromGitHub {
owner = "MalpenZibo";
repo = "ashell";
tag = finalAttrs.version;
hash = "sha256-X9TU866PAzaf52qKsCpeJvwE0suu1lJndHNQdPg51HM=";
hash = "sha256-QRNEc2HNqA1tZk/jW/MXDwXda58yNlkw86SCTjH1/1w=";
};
cargoHash = "sha256-nhYbehlgB8pzMoj39G0BHRca9mIT+0QjUaebCx+DDE0=";
cargoHash = "sha256-bLZcRASBGV9Y/QlDVBdOl2ElZDLI1KUAh5MlOsjmlKs=";
nativeBuildInputs = [
pkg-config
@ -45,10 +46,12 @@ rustPlatform.buildRustPackage (finalAttrs: {
]
++ finalAttrs.runtimeDependencies;
passthru.updateScript = nix-update-script { };
meta = {
description = "Ready to go Wayland status bar for Hyprland";
homepage = "https://github.com/MalpenZibo/ashell";
license = lib.licenses.mit;
license = lib.licenses.gpl3Plus;
mainProgram = "ashell";
maintainers = with lib.maintainers; [ justdeeevin ];
platforms = lib.platforms.linux;

View file

@ -7,8 +7,10 @@
testers,
static ? stdenv.hostPlatform.isStatic,
snappySupport ? false,
lz4,
snappy,
zlib,
zstd,
}:
@ -51,7 +53,8 @@ stdenv.mkDerivation (finalAttrs: {
lz4
zlib
zstd
];
]
++ lib.optional snappySupport snappy;
cmakeFlags = [
"-DBUILD_STATIC=${if static then "ON" else "OFF"}"
@ -64,7 +67,8 @@ stdenv.mkDerivation (finalAttrs: {
"-DBUILD_EXAMPLES=OFF"
"-DBUILD_BENCHMARKS=OFF"
"-DBUILD_TESTS=${if finalAttrs.finalPackage.doCheck then "ON" else "OFF"}"
];
]
++ lib.optional snappySupport "-DDEACTIVATE_SNAPPY=OFF";
doCheck = !static;

View file

@ -11,16 +11,16 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "cargo-binstall";
version = "1.19.1";
version = "1.20.0";
src = fetchFromGitHub {
owner = "cargo-bins";
repo = "cargo-binstall";
tag = "v${finalAttrs.version}";
hash = "sha256-b4S8oPK1U84Oy3hhJSxJxToaFF5l4V2Tea0kGn3hW0A=";
hash = "sha256-EnHBXdaER23fvYJ3iW4JqpE1Qap/sQottkqllNA2n18=";
};
cargoHash = "sha256-E+exhtfJiOTQIZm44WyA0yptUn7wymXFRlDyAsshcKA=";
cargoHash = "sha256-p/IfFnFB7vJPVJH2SvnLagXh9zxLgNxEcZILQcIqnVo=";
nativeBuildInputs = [
pkg-config

View file

@ -7,7 +7,7 @@
nodejs,
openssl,
pkg-config,
pnpm_9,
pnpm_10,
fetchPnpmDeps,
pnpmConfigHook,
rustPlatform,
@ -31,10 +31,10 @@ stdenv.mkDerivation (finalAttrs: {
version
src
;
pnpm = pnpm_9;
pnpm = pnpm_10;
fetcherVersion = 3;
hash = "sha256-DiRho0tmR/4XJi7cAZxesVA1iR8uiwknCfmIP2x9i5I=";
fetcherVersion = 4;
hash = "sha256-m7haAF5ZIYG5NfsPwtzVF6Z83h/I4uT0YhNBk4ZXdpo=";
};
nativeBuildInputs = [
@ -43,7 +43,7 @@ stdenv.mkDerivation (finalAttrs: {
nodejs
pkg-config
pnpmConfigHook
pnpm_9
pnpm_10
rustPlatform.cargoCheckHook
rustPlatform.cargoSetupHook
wrapGAppsHook4

View file

@ -6,13 +6,13 @@
buildGoModule (finalAttrs: {
pname = "cent";
version = "2.0.0";
version = "2.2.0";
src = fetchFromGitHub {
owner = "xm1k3";
repo = "cent";
tag = "v${finalAttrs.version}";
hash = "sha256-AmOq+n+TcpwDgFjFsFNVl/fAIAJbqYdoR2P1dasb8h8=";
hash = "sha256-dblykbFoYc45czbOnxrfR+HIBEyUo9JlzprhwOkCG58=";
};
vendorHash = "sha256-sn4ZIDP07u9dwVJHy7KrQFZHsGrqpkM8CzcIbNMDiIo=";

View file

@ -21,13 +21,13 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "cinny-desktop";
# We have to be using the same version as cinny-web or this isn't going to work.
version = "4.12.1";
version = "4.12.2";
src = fetchFromGitHub {
owner = "cinnyapp";
repo = "cinny-desktop";
tag = "v${finalAttrs.version}";
hash = "sha256-SRtnib5C9YlNOC1YgXZVFgO2dIHSmk+I20Ltf4XkJ6E=";
hash = "sha256-gaTgNTn0/HHzULHRL03+t73MEUOGdqcEyqaIt8CWA0k=";
};
sourceRoot = "${finalAttrs.src.name}/src-tauri";

View file

@ -7,17 +7,17 @@
buildNpmPackage (finalAttrs: {
pname = "cinny-unwrapped";
# Remember to update cinny-desktop when bumping this version.
version = "4.12.1";
version = "4.12.2";
# nixpkgs-update: no auto update
src = fetchFromGitHub {
owner = "cinnyapp";
repo = "cinny";
tag = "v${finalAttrs.version}";
hash = "sha256-s9nu6hYe0OvRcp8n2cOJnhEzIV+nyjnfwTrY477XDT8=";
hash = "sha256-UF5MwV02G0oYIXtvyzHn+DifYM8PFlyb9DZ4w1fuyDE=";
};
npmDepsHash = "sha256-e37tSrqrEXGH2uInFAiikHNwJ13gXlG50SeYF/HO0z4=";
npmDepsHash = "sha256-8SyUFv1wgnqfSyBlykmeGI8RAmFt5Q5uS6OFLi+qPPY=";
# Skip rebuilding native modules since they're not needed for the web app
npmRebuildFlags = [

View file

@ -5,16 +5,19 @@
stdenv,
pkg-config,
openssl,
versionCheckHook,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "click";
version = "0.6.3";
__structuredAttrs = true;
src = fetchFromGitHub {
owner = "databricks";
repo = "click";
rev = "v${finalAttrs.version}";
tag = "v${finalAttrs.version}";
hash = "sha256-tYSbyDipZg6Qj/CWk1QVUT5AG8ncTt+5V1+ekpmsKXA=";
};
@ -24,15 +27,14 @@ rustPlatform.buildRustPackage (finalAttrs: {
buildInputs = lib.optionals stdenv.hostPlatform.isLinux [ openssl ];
nativeInstallCheckInputs = [ versionCheckHook ];
doInstallCheck = true;
meta = {
description = "Command Line Interactive Controller for Kubernetes";
homepage = "https://github.com/databricks/click";
license = [ lib.licenses.asl20 ];
maintainers = [ lib.maintainers.mbode ];
platforms = [
"x86_64-linux"
"x86_64-darwin"
];
mainProgram = "click";
};
})

View file

@ -9,16 +9,16 @@
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "codesnap";
version = "0.13.1";
version = "0.13.4";
src = fetchFromGitHub {
owner = "codesnap-rs";
repo = "codesnap";
tag = "v${finalAttrs.version}";
hash = "sha256-baTIxqfxxoHl7h81pboFlze5m/EMiEx9YOMfV0UPESI=";
hash = "sha256-cMxXzLvnqsloKT7ixMlQnAq+ZempLeEzkWyWxG4jt9Y=";
};
cargoHash = "sha256-bi5vvUDMI4WxIpv0sHESmLg3vwAIbNQ11pbJDuSe8z4=";
cargoHash = "sha256-QMpncisumxF02lFQ8xsZiR5AYZVSHWlAuuFDg0ZoPtI=";
nativeBuildInputs = [ pkg-config ];

View file

@ -8,15 +8,15 @@
}:
let
version = "7.1.220";
version = "7.1.230";
srcs = {
x86_64-linux = fetchurl {
url = "https://github.com/aunetx/deezer-linux/releases/download/v${version}/deezer-desktop-${version}-x64.tar.xz";
hash = "sha256-q4j4S88c7xsC+Ax7XY1EVbqRRJXH+JzLrZRRB6rfQOE=";
hash = "sha256-OP5ceyGQQFRgW1GZPElxdjkYikNVMkvomkXCr9dD67Y=";
};
aarch64-linux = fetchurl {
url = "https://github.com/aunetx/deezer-linux/releases/download/v${version}/deezer-desktop-${version}-arm64.tar.xz";
hash = "sha256-g94qn+EHr8Dwn21L7z3W7Z5+LJoVSQcAEXHpJiAdbJg=";
hash = "sha256-IiUZgMHdhkU0B5uDLARHpcCUxlsZ4+rj5sAKJXZpcBw=";
};
};

View file

@ -81,7 +81,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
meta = {
description = "Cognition's Devin Agent CLI";
homepage = "https://devin.ai/";
homepage = "https://devin.ai/cli";
license = lib.licenses.unfree;
sourceProvenance = [ lib.sourceTypes.binaryBytecode ];
maintainers = with lib.maintainers; [

View file

@ -70,9 +70,6 @@ stdenv.mkDerivation (finalAttrs: {
homepage = "https://github.com/NVIDIA/egl-wayland/";
license = lib.licenses.mit;
platforms = lib.platforms.linux ++ lib.platforms.freebsd;
maintainers = with lib.maintainers; [
hedning
ccicnce113424
];
maintainers = with lib.maintainers; [ ccicnce113424 ];
};
})

View file

@ -40,9 +40,6 @@ stdenv.mkDerivation (finalAttrs: {
homepage = "https://github.com/NVIDIA/eglexternalplatform";
license = lib.licenses.mit;
platforms = lib.platforms.linux ++ lib.platforms.freebsd;
maintainers = with lib.maintainers; [
hedning
ccicnce113424
];
maintainers = with lib.maintainers; [ ccicnce113424 ];
};
})

View file

@ -16,16 +16,16 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "elan";
version = "4.2.2";
version = "4.2.3";
src = fetchFromGitHub {
owner = "leanprover";
repo = "elan";
rev = "v${finalAttrs.version}";
hash = "sha256-2Z/lw6tCloY6Lg+zHkYbfazLXMks6bxYBF5PxhI+654=";
hash = "sha256-Ael2hla+jqiaP8FfYYQ0u3V8cVt+CEFEQU7jB3LYG2E=";
};
cargoHash = "sha256-QilFETnaZtOVIwl+IrCvNjnofnQfEqC0ILsT1nQShgw=";
cargoHash = "sha256-MDe/QBE1gd/4yMAuwBga8x9yv3duf3vaudMongurtQI=";
nativeBuildInputs = [
pkg-config

View file

@ -6,10 +6,10 @@
let
pname = "fflogs";
version = "9.3.61";
version = "9.3.65";
src = fetchurl {
url = "https://github.com/RPGLogs/Uploaders-fflogs/releases/download/v${version}/fflogs-v${version}.AppImage";
hash = "sha256-QBiZR8wjhMsLguzBaM21mADlR1hKHdBuK66DcSzyVtQ=";
hash = "sha256-HsanoX1iJpLC8p64H4enlo20X6LOBNAxkubwPBp5juA=";
};
extracted = appimageTools.extractType2 { inherit pname version src; };
in

View file

@ -20,13 +20,13 @@ let
in
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "freetube";
version = "0.24.0";
version = "0.24.1";
src = fetchFromGitHub {
owner = "FreeTubeApp";
repo = "FreeTube";
tag = "v${finalAttrs.version}-beta";
hash = "sha256-4XyN7ENsDwLNB/dt7pp8z0sbdmHSNIyVEHlp5GXIues=";
hash = "sha256-oo5ozdP3d82jY8OOYrt568MoSfPmwBoitdtgESiRMlE=";
};
# Darwin requires writable Electron dist

View file

@ -6,16 +6,16 @@
buildGoModule (finalAttrs: {
pname = "gat";
version = "0.27.3";
version = "0.30.2";
src = fetchFromGitHub {
owner = "koki-develop";
repo = "gat";
tag = "v${finalAttrs.version}";
hash = "sha256-PCHCBYflW+wUYzwlMOSno/xG5UX34QM9aG0RaCtC9h0=";
hash = "sha256-xDzjahtPD53sCmZOFbogrU7/y+YvpVC0l5K2dtTks1o=";
};
vendorHash = "sha256-tFEir5386McMi5i6Mk/6B4KPZhEucOcWAO2jECouDDg=";
vendorHash = "sha256-HHhvJNuoUHjHdQ864YpUWxRHCXeL/cd4EHSFq3N2mo4=";
env.CGO_ENABLED = 0;

View file

@ -11,15 +11,19 @@
let
inherit (stdenv.hostPlatform.uname) processor;
version = "6.4.0";
version = "6.7.1";
sources = {
"x86_64-linux" = {
url = "https://cdn.geekbench.com/Geekbench-${version}-Linux.tar.gz";
hash = "sha256-Q4MwU3dIFheKKSMxzCBZI8XoForaN41BuRGVMhJaUKw=";
hash = "sha256-Ddypd9622dtL2GZIX5QI5y4oadDeoHN7GNS/5HKFis4=";
};
"aarch64-linux" = {
url = "https://cdn.geekbench.com/Geekbench-${version}-LinuxARMPreview.tar.gz";
hash = "sha256-PZ95w2X4sqTLZGZ5wygt7WjSK4Gfgtdh/UCPo+8Ysc8=";
hash = "sha256-blmsuD5t6jZx4uKVNl/DfED90oDNvd1QrPJIkQ4UoOM=";
};
"riscv64-linux" = {
url = "https://cdn.geekbench.com/Geekbench-${version}-LinuxRISCVPreview.tar.gz";
hash = "sha256-TByNeLqqHrnrLcX/meXNy6Evvebf0/xWnUohd/TwiAk=";
};
};
geekbench_avx2 = lib.optionalString stdenv.hostPlatform.isx86_64 "geekbench_avx2";

View file

@ -8,15 +8,15 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "gitlab-ci-ls";
version = "1.3.2";
version = "1.3.3";
src = fetchFromGitHub {
owner = "alesbrelih";
repo = "gitlab-ci-ls";
rev = "${finalAttrs.version}";
hash = "sha256-b//Yi+7jOQv+pHyeS/t3OSBMCZZ34sP8xXCNivlShYQ=";
hash = "sha256-VA1y24JObxUcY8BPq9xtbajBrFlcq5H1wi8j7jQtsY4=";
};
cargoHash = "sha256-BCV5LU8cVf40vCQCN56dlWiyvfvwF4nPUcLb+mOfsok=";
cargoHash = "sha256-SNc2mgfUaKYGsIDnpigMciO/l8EavlCbE8gCUSdj7aA=";
nativeBuildInputs = [ pkg-config ];
buildInputs = [ openssl ];

View file

@ -6,7 +6,7 @@
python3Packages.buildPythonApplication (finalAttrs: {
pname = "gogdl";
version = "1.2.1";
version = "1.2.2";
pyproject = true;
src = fetchFromGitHub {
@ -14,7 +14,7 @@ python3Packages.buildPythonApplication (finalAttrs: {
repo = "heroic-gogdl";
tag = "v${finalAttrs.version}";
fetchSubmodules = true;
hash = "sha256-qYarDcwrVrTpLHQYdWQvXL5+V1wMyL06+n5t6LXKBHI=";
hash = "sha256-gXAlZa4rml8fH54jpOIXZN0/1iieLpZwpii5ICHQ2Sc=";
};
build-system = with python3Packages; [

View file

@ -0,0 +1,28 @@
{
lib,
buildGoModule,
fetchFromGitHub,
nixosTests,
}:
buildGoModule rec {
pname = "gs1200-exporter";
version = "2.11.12";
__structuredAttrs = true;
src = fetchFromGitHub {
owner = "robinelfrink";
repo = "gs1200-exporter";
tag = "v${version}";
hash = "sha256-8s2VgaqYXp9PN2oNU/sWpjQjDPSWolbWEVSZcx9Lh3M=";
};
vendorHash = "sha256-204bFaywOolKVNoeH/w72Ba1PYAVgQawEmlaEXgRaRY=";
passthru.tests = {
inherit (nixosTests) gs1200-exporter;
};
meta = {
description = "Prometheus exporter for Zyxel GS1200 switches";
homepage = "https://github.com/robinelfrink/gs1200-exporter";
license = lib.licenses.asl20;
maintainers = with lib.maintainers; [ DerGrumpf ];
mainProgram = "gs1200-exporter";
};
}

View file

@ -10,16 +10,16 @@
buildGoModule (finalAttrs: {
pname = "helmfile";
version = "1.5.0";
version = "1.5.2";
src = fetchFromGitHub {
owner = "helmfile";
repo = "helmfile";
rev = "v${finalAttrs.version}";
hash = "sha256-Uqm4cnhuILGmdwyZkLNJXrBF4H/zZkg7PfdE//jLP5A=";
hash = "sha256-5eWD4Hr65DDWAXHXk0A9Mt90ZNcGt+6NXH5ggSHA4Fk=";
};
vendorHash = "sha256-8JEKAiEwkzjFzoMVyPd2Wmpt/Fjh+j9ocmIn5cQBVqE=";
vendorHash = "sha256-bbMBesSbDMUqaJWm3Pgauz6tNw8gB0H5vQWKZJSn3sQ=";
proxyVendor = true; # darwin/linux hash mismatch

View file

@ -20,13 +20,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "hwinfo";
version = "25.3";
version = "25.4";
src = fetchFromGitHub {
owner = "opensuse";
repo = "hwinfo";
rev = finalAttrs.version;
hash = "sha256-lc+x81aPbfoAV8YXH77r+BBERUFbv4stSPq3U36HXAI=";
hash = "sha256-XFb87IuFXYmFnlrjinz7Q+FhoRtpdToW9tos3pFzQYE=";
};
nativeBuildInputs = [

View file

@ -8,15 +8,18 @@
libsForQt5,
}:
stdenv.mkDerivation rec {
stdenv.mkDerivation (finalAttrs: {
pname = "i7z";
version = "0.27.4";
strictDeps = true;
__structuredAttrs = true;
src = fetchFromGitHub {
owner = "DimitryAndric";
repo = "i7z";
rev = "v${version}";
sha256 = "00c4ng30ry88hcya4g1i9dngiqmz3cs31x7qh1a10nalxn1829xy";
tag = "v${finalAttrs.version}";
hash = "sha256-vieBgu1UWRBUgPj0MDQbv+L4bEsxPKI8gwj5DMazhAE=";
};
buildInputs = [ ncurses ] ++ lib.optional withGui libsForQt5.qtbase;
@ -24,15 +27,15 @@ stdenv.mkDerivation rec {
patches = [
(fetchpatch {
url = "https://salsa.debian.org/debian/i7z/raw/ad1359764ee7a860a02e0c972f40339058fa9369/debian/patches/fix-insecure-tempfile.patch";
sha256 = "0ifg06xjw14y4fnzzgkhqm4sv9mcdzgi8m2wffq9z8b1r0znya3s";
hash = "sha256-eihvP8hhoZ+wc1xUFN9vrKatScVwvv+tI54ELrsBz0U=";
})
(fetchpatch {
url = "https://salsa.debian.org/debian/i7z/raw/ad1359764ee7a860a02e0c972f40339058fa9369/debian/patches/nehalem.patch";
sha256 = "1ys6sgm01jkqb6d4y7qc3h89dzph8jjjcfya5c5jcm7dkxlzjq8a";
hash = "sha256-CmH5aZ/tVCYLK8o7JqVE8P6WEBwMH0+aWXjKAOrTRvs=";
})
(fetchpatch {
url = "https://salsa.debian.org/debian/i7z/raw/ad1359764ee7a860a02e0c972f40339058fa9369/debian/patches/hyphen-used-as-minus-sign.patch";
sha256 = "1ji2qvdyq0594cpqz0dlsfggvw3rm63sygh0jxvwjgxpnhykhg1p";
hash = "sha256-Nzw4PbS3P8l3lwA+r4epefD9ntO0gY8vI6kA7NvGIso=";
})
./qt5.patch
];
@ -61,4 +64,4 @@ stdenv.mkDerivation rec {
# broken on ARM
platforms = [ "x86_64-linux" ];
};
}
})

View file

@ -6,20 +6,26 @@
krita-plugin-gmic
],
krita-unwrapped,
wrapGAppsHook3,
}:
symlinkJoin {
pname = "krita";
inherit (krita-unwrapped)
version
buildInputs
nativeBuildInputs
meta
;
nativeBuildInputs = krita-unwrapped.nativeBuildInputs ++ [
wrapGAppsHook3
];
paths = [ krita-unwrapped ] ++ binaryPlugins;
postBuild = ''
gappsWrapperArgsHook
wrapQtApp "$out/bin/krita" \
"''${gappsWrapperArgs[@]}" \
--prefix PYTHONPATH : "$PYTHONPATH" \
--set KRITA_PLUGIN_PATH "$out/lib/kritaplugins"
'';

View file

@ -11,8 +11,8 @@
},
{
"pname": "AudibleApi",
"version": "10.1.5.1",
"hash": "sha256-XSLNUNXlOj0YCqe4Ix+mvbR64Mr/mQgeXTif0q+OSCo="
"version": "10.2.0.1",
"hash": "sha256-z0IzuOE8eDWyyz7gf1gMGdVMMIhs6axoAceaafaZbbw="
},
{
"pname": "Avalonia",
@ -626,13 +626,13 @@
},
{
"pname": "ReactiveUI",
"version": "23.2.1",
"hash": "sha256-Na0BtJBMBdz8JiK+2cbaM/7lkd+tuGL9Lr5gEVPfPX0="
"version": "23.2.28",
"hash": "sha256-GaPH7EqdaamvhyVphO9TLfD5dFMVV2gA33JwbR6Lzoc="
},
{
"pname": "ReactiveUI.Avalonia",
"version": "12.0.1",
"hash": "sha256-MoNUvbQ5XTuDNVPC4bVHcxRtRiU/oduaHCRL6IfKb+Q="
"version": "12.0.2",
"hash": "sha256-bFylVd7nljJMBszmAWNJa9R3Q03s/Bp2M2+GJKjYxWU="
},
{
"pname": "Serilog",
@ -701,23 +701,23 @@
},
{
"pname": "Splat",
"version": "19.3.1",
"hash": "sha256-ri8qniMdAzAO4cjjVfuSFxMM6MvxFrG6+d2cPWJeLUE="
"version": "19.4.1",
"hash": "sha256-+huQc0B/7XQA7zPf+4jFLXfBj6Y8K9gRRp7tATKuXH8="
},
{
"pname": "Splat.Builder",
"version": "19.3.1",
"hash": "sha256-XN/3+5BEaq6v17eWKFUOqqCmVWJLEVQBm5cvejxetw8="
"version": "19.4.1",
"hash": "sha256-fVTi/MpA4t6QR3+NgNTL3lRwcVCkKFAZYHGDvChVadM="
},
{
"pname": "Splat.Core",
"version": "19.3.1",
"hash": "sha256-Fav212nMhUGO5/1zFKevXVm21MH+x7NTqgq1jD1WRKw="
"version": "19.4.1",
"hash": "sha256-0XxTbnSH8yLC6XSbnhm1qv3YlDYTzpvFJlt/6mz0o/g="
},
{
"pname": "Splat.Logging",
"version": "19.3.1",
"hash": "sha256-rTXD2bqIa/IjeN/mFv9n9mkL2rujEg1iIUPimVpYLBQ="
"version": "19.4.1",
"hash": "sha256-nk4NgktArB7v9HNdu9NnewYQcwaQl+fZlRZbieXW6Dw="
},
{
"pname": "SQLitePCLRaw.bundle_e_sqlite3",

View file

@ -16,13 +16,13 @@
buildDotnetModule rec {
pname = "libation";
version = "13.4.4";
version = "13.4.5";
src = fetchFromGitHub {
owner = "rmcrackan";
repo = "Libation";
tag = "v${version}";
hash = "sha256-qOoPSpNzm31iUpf0tOR5BoL4M0kjZbvNCk3Mb6eN1WI=";
hash = "sha256-t4Fz7aqQg1WPqSKvvVbSx45M6+UNGXacFHXGjzNW67A=";
};
sourceRoot = "${src.name}/Source";

View file

@ -11,13 +11,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "lprint";
version = "1.3.1";
version = "1.4.0";
src = fetchFromGitHub {
owner = "michaelrsweet";
repo = "lprint";
rev = "v${finalAttrs.version}";
hash = "sha256-1OOLGQ8S4oRNSJanX/AzJ+g5F+jYnE/+o+ie5ucY22U=";
hash = "sha256-r5mOwkU828btDdt0y7JrEl6KSim8VaF/y4R58zPX3eI=";
};
outputs = [

View file

@ -10,11 +10,11 @@
stdenv.mkDerivation (finalAttrs: {
pname = "maestro";
version = "2.5.1";
version = "2.6.0";
src = fetchurl {
url = "https://github.com/mobile-dev-inc/maestro/releases/download/cli-${finalAttrs.version}/maestro.zip";
hash = "sha256-LZJL/TfMyrykOKcnITZIy/5Pi7cRVZ7I6dGZ3AmlzlI=";
hash = "sha256-gBhRBaXX4ifjs/vPIl9FsxJQjqZ2qfyOGxqhysi5/24=";
};
dontUnpack = true;

View file

@ -5,13 +5,14 @@
installShellFiles,
libarchive,
p7zip,
testers,
mas,
versionCheckHook,
}:
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "mas";
version = "6.0.1";
__structuredAttrs = true;
src =
let
# nix store prefetch-file https://github.com/mas-cli/mas/releases/download/v$VERSION/mas-$VERSION-$ARCH.pkg
@ -65,12 +66,8 @@ stdenvNoCC.mkDerivation (finalAttrs: {
runHook postInstall
'';
passthru.tests = {
version = testers.testVersion {
package = mas;
command = "mas version";
};
};
nativeInstallCheckInputs = [ versionCheckHook ];
doInstallCheck = true;
meta = {
description = "Mac App Store command line interface";

View file

@ -7,13 +7,13 @@
}:
stdenvNoCC.mkDerivation {
pname = "material-symbols";
version = "4.0.0-unstable-2026-05-08";
version = "4.0.0-unstable-2026-06-05";
src = fetchFromGitHub {
owner = "google";
repo = "material-design-icons";
rev = "5a4e1b7fd26f11ce3d2abf7d7fcd13274f874e6c";
hash = "sha256-XVza/duC2hsBrT6Ty1XxJy0m/lpuBt2rVoUo5B1JmUc=";
rev = "27aa4d49e4fabcb2a7f3acc86d205d33b159fad3";
hash = "sha256-l8uXZZZ0rtQIYiEua8xmpuacLiR8hVjclAyc9dUI8z8=";
sparseCheckout = [ "variablefont" ];
};

View file

@ -4,19 +4,22 @@
fetchFromGitHub,
autoreconfHook,
autoconf-archive,
ocamlPackages,
ocaml-ng,
pkg-config,
zlib,
}:
stdenv.mkDerivation rec {
let
ocamlPackages = ocaml-ng.ocamlPackages_4_14;
in
stdenv.mkDerivation (finalAttrs: {
pname = "mldonkey";
version = "3.2.1";
src = fetchFromGitHub {
owner = "ygrek";
repo = "mldonkey";
tag = "release-${lib.replaceStrings [ "." ] [ "-" ] version}";
tag = "release-${lib.replaceStrings [ "." ] [ "-" ] finalAttrs.version}";
hash = "sha256-Dbb7163CdqHY7/FJY2yWBFRudT+hTFT6fO4sFgt6C/A=";
};
@ -30,6 +33,7 @@ stdenv.mkDerivation rec {
'';
strictDeps = true;
__structuredAttrs = true;
nativeBuildInputs = [
autoreconfHook
@ -70,4 +74,4 @@ stdenv.mkDerivation rec {
license = lib.licenses.gpl2Only;
platforms = lib.platforms.unix;
};
}
})

View file

@ -60,7 +60,7 @@ python3Packages.buildPythonApplication (finalAttrs: {
description = "MPRIS 2 support for mpd";
homepage = "https://github.com/eonpatapon/mpDris2/";
license = lib.licenses.gpl3Plus;
maintainers = [ ];
maintainers = with lib.maintainers; [ acidbong ];
platforms = lib.platforms.unix;
mainProgram = "mpDris2";
};

View file

@ -6,13 +6,13 @@
}:
buildGoModule (finalAttrs: {
pname = "n8n-task-runner-launcher";
version = "1.4.5";
version = "1.4.6";
src = fetchFromGitHub {
owner = "n8n-io";
repo = "task-runner-launcher";
tag = finalAttrs.version;
hash = "sha256-7V//x/AG/3dNWIAQpjBrcOJNn9T9iboKEvJvDV2EK5A=";
hash = "sha256-9XbeAssVQBcAfuiCgLEAX0CkI9u1410PE2HOcrI2Uxs=";
};
vendorHash = "sha256-5dcIELsNFGB5qTmfpY/YRWeN2z9GdanysGw4Lqpfsi0=";

View file

@ -60,10 +60,7 @@ stdenv.mkDerivation (finalAttrs: {
description = "Bash completions for Nix, NixOS, and NixOps";
license = lib.licenses.bsd3;
platforms = lib.platforms.all;
maintainers = with lib.maintainers; [
hedning
ncfavier
];
maintainers = with lib.maintainers; [ ncfavier ];
# Set a lower priority such that Nix wins in case of conflicts.
priority = 10;
};

View file

@ -37,7 +37,6 @@ stdenvNoCC.mkDerivation (finalAttrs: {
platforms = lib.platforms.all;
maintainers = with lib.maintainers; [
olejorgenb
hedning
ma27
];
};

View file

@ -6,16 +6,16 @@
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "nixpkgs-vet";
version = "0.3.0";
version = "0.3.2";
src = fetchFromGitHub {
owner = "NixOS";
repo = "nixpkgs-vet";
tag = finalAttrs.version;
hash = "sha256-Rk1p6qAqAtl5bwg9dNZ0yc4m1yOOxybWvTwfuNcOkFQ=";
tag = "v${finalAttrs.version}";
hash = "sha256-GJhN77zLtV2fUEL5wxjcybtDqUa6ODg39d3UxuOrapo=";
};
cargoHash = "sha256-GaQ2ldsGabsDMx1bHuZwnSvtPp1LgPkj2C07cnEBdDY=";
cargoHash = "sha256-zTh18jec0trJP4q3rYheHZz01lbkhpDaotuPbvgzMpo=";
doCheck = false;
@ -23,6 +23,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
meta = {
description = "Tool to vet (check) Nixpkgs, including its pkgs/by-name directory";
changelog = "https://github.com/NixOS/nixpkgs-vet/blob/${finalAttrs.src.rev}/CHANGELOG.md";
homepage = "https://github.com/NixOS/nixpkgs-vet";
license = lib.licenses.mit;
mainProgram = "nixpkgs-vet";

View file

@ -9,7 +9,7 @@
let
pname = "notesnook";
version = "3.3.20";
version = "3.3.21";
inherit (stdenv.hostPlatform) system;
throwSystem = throw "Unsupported system: ${system}";
@ -27,10 +27,10 @@ let
url = "https://github.com/streetwriters/notesnook/releases/download/v${version}/notesnook_${suffix}";
hash =
{
x86_64-linux = "sha256-4TMQAs4ovBc2HFPxu0aNGZpA+N/xUBgcforJqT7jSCg=";
aarch64-linux = "sha256-royjfwu8bU6FJY3M18c0fRoRoM1dwWzhkuftdZ/XKeI=";
x86_64-darwin = "sha256-iqZbOlSkCXMsDYUsImAVROeKb11Rj6vKVbyTDGayfzY=";
aarch64-darwin = "sha256-ozPAwuM3mTq8r9iD+kKAXzeb8Z5xYaMBbHyXx4UEhY8=";
x86_64-linux = "sha256-NmhV+x5HrKBO7BX1bJyjChKQF/j38kQqJ3x0amSXzGU=";
aarch64-linux = "sha256-IU4hF/ol4pyh+ABTri2aqwqaB+cfrHLtsF7wrqE+wEY=";
x86_64-darwin = "sha256-YhJvkKreWUReEgs4R9lWV0/cx3d0hrjKTHZn0hDsp3k=";
aarch64-darwin = "sha256-9CTGpCPJY6sq6JWDpoCTyOTt/vtCazDaoDzFFUzR9zg=";
}
.${system} or throwSystem;
};

View file

@ -2,22 +2,22 @@
lib,
fetchFromGitHub,
ocamlPackages,
menhir,
}:
ocamlPackages.buildDunePackage rec {
ocamlPackages.buildDunePackage (finalAttrs: {
pname = "obelisk";
version = "0.8.1";
src = fetchFromGitHub {
owner = "Lelio-Brun";
repo = pname;
rev = "v${version}";
sha256 = "sha256-JJ8k9/6awKZH87T9Ut8x/hlshiUI6sy2fZtY6x2dIIk=";
repo = "obelisk";
tag = "v${finalAttrs.version}";
hash = "sha256-JJ8k9/6awKZH87T9Ut8x/hlshiUI6sy2fZtY6x2dIIk=";
};
strictDeps = true;
nativeBuildInputs = [ menhir ];
nativeBuildInputs = with ocamlPackages; [ menhir ];
buildInputs = with ocamlPackages; [ re ];
meta = {
@ -27,4 +27,4 @@ ocamlPackages.buildDunePackage rec {
maintainers = [ lib.maintainers.vbgl ];
homepage = "https://github.com/Lelio-Brun/Obelisk";
};
}
})

View file

@ -8,16 +8,16 @@
buildGoModule rec {
pname = "omnictl";
version = "1.8.0";
version = "1.8.2";
src = fetchFromGitHub {
owner = "siderolabs";
repo = "omni";
rev = "v${version}";
hash = "sha256-8oTLe4ZGXqL62h+AbjjKv/SmDd9cMvFO3k/0K3VdrNI=";
hash = "sha256-cgFbez5SqQa0aOMXEijvepJgWO4I6HDww6Ymjf9KTOI=";
};
vendorHash = "sha256-yO9b26bXCg5pSXX65vQf/8YII/92sDjGJMK40zu/3s8=";
vendorHash = "sha256-b+1ysxtnzaY1G2aiZt+cke5k5NOL93jciTpf0VB1F4w=";
ldflags = [
"-s"

View file

@ -1,12 +1,13 @@
{
stdenv,
lib,
stdenv,
fetchFromGitHub,
cmake,
gfortran,
fftwSinglePrec,
doxygen,
swig,
graphviz,
enablePython ? false,
python3Packages,
enableOpencl ? true,
@ -15,18 +16,27 @@
config,
enableCuda ? config.cudaSupport,
cudaPackages,
addDriverRunpath,
autoAddDriverRunpath,
# passthru
nix-update-script,
}:
stdenv.mkDerivation (finalAttrs: {
let
effectiveStdenv = if enableCuda then cudaPackages.backendStdenv else stdenv;
in
effectiveStdenv.mkDerivation (finalAttrs: {
pname = "openmm";
version = "8.5.1";
version = "8.5.2";
__structuredAttrs = true;
strictDeps = true;
src = fetchFromGitHub {
owner = "openmm";
repo = "openmm";
rev = finalAttrs.version;
hash = "sha256-YGoQGOP6Use4ivhxlWfKMpEjpm5ovFH1Qf0yVK5jr48=";
tag = finalAttrs.version;
hash = "sha256-9mOgnMgRU7zE9UWJ03VNoOTt76nPTHXZ4xkSKtOTwng=";
};
# "This test is stochastic and may occasionally fail". It does.
@ -42,6 +52,7 @@ stdenv.mkDerivation (finalAttrs: {
gfortran
swig
doxygen
graphviz # doxygen missing components: dot
python3Packages.python
]
++ lib.optionals enablePython [
@ -49,7 +60,10 @@ stdenv.mkDerivation (finalAttrs: {
python3Packages.installer
python3Packages.wheel
]
++ lib.optional enableCuda addDriverRunpath;
++ lib.optionals enableCuda [
cudaPackages.cuda_nvcc
autoAddDriverRunpath
];
buildInputs = [
fftwSinglePrec
@ -58,7 +72,12 @@ stdenv.mkDerivation (finalAttrs: {
ocl-icd
opencl-headers
]
++ lib.optional enableCuda cudaPackages.cudatoolkit;
++ lib.optionals enableCuda [
cudaPackages.cuda_cudart # CUDA::cuda_driver (driver stub)
cudaPackages.cuda_nvrtc # runtime kernel compilation
cudaPackages.cuda_profiler_api # cudaProfiler.h
cudaPackages.libcufft # CUDA::cufft
];
propagatedBuildInputs = lib.optionals enablePython (
with python3Packages;
@ -71,31 +90,29 @@ stdenv.mkDerivation (finalAttrs: {
);
cmakeFlags = [
"-DBUILD_TESTING=ON"
"-DOPENMM_BUILD_AMOEBA_PLUGIN=ON"
"-DOPENMM_BUILD_CPU_LIB=ON"
"-DOPENMM_BUILD_C_AND_FORTRAN_WRAPPERS=ON"
"-DOPENMM_BUILD_DRUDE_PLUGIN=ON"
"-DOPENMM_BUILD_PME_PLUGIN=ON"
"-DOPENMM_BUILD_RPMD_PLUGIN=ON"
"-DOPENMM_BUILD_SHARED_LIB=ON"
(lib.cmakeBool "BUILD_TESTING" true)
(lib.cmakeBool "OPENMM_BUILD_AMOEBA_PLUGIN" true)
(lib.cmakeBool "OPENMM_BUILD_CPU_LIB" true)
(lib.cmakeBool "OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS" true)
(lib.cmakeBool "OPENMM_BUILD_DRUDE_PLUGIN" true)
(lib.cmakeBool "OPENMM_BUILD_PME_PLUGIN" true)
(lib.cmakeBool "OPENMM_BUILD_RPMD_PLUGIN" true)
(lib.cmakeBool "OPENMM_BUILD_SHARED_LIB" true)
]
++ lib.optionals enablePython [
"-DOPENMM_BUILD_PYTHON_WRAPPERS=ON"
(lib.cmakeBool "OPENMM_BUILD_PYTHON_WRAPPERS" true)
]
++ lib.optionals enableOpencl [
"-DOPENMM_BUILD_OPENCL_LIB=ON"
"-DOPENMM_BUILD_AMOEBA_OPENCL_LIB=ON"
"-DOPENMM_BUILD_DRUDE_OPENCL_LIB=ON"
"-DOPENMM_BUILD_RPMD_OPENCL_LIB=ON"
(lib.cmakeBool "OPENMM_BUILD_AMOEBA_OPENCL_LIB" true)
(lib.cmakeBool "OPENMM_BUILD_DRUDE_OPENCL_LIB" true)
(lib.cmakeBool "OPENMM_BUILD_OPENCL_LIB" true)
(lib.cmakeBool "OPENMM_BUILD_RPMD_OPENCL_LIB" true)
]
++ lib.optionals enableCuda [
"-DCUDA_SDK_ROOT_DIR=${cudaPackages.cudatoolkit}"
"-DOPENMM_BUILD_AMOEBA_CUDA_LIB=ON"
"-DOPENMM_BUILD_CUDA_LIB=ON"
"-DOPENMM_BUILD_DRUDE_CUDA_LIB=ON"
"-DOPENMM_BUILD_RPMD_CUDA_LIB=ON"
"-DCMAKE_LIBRARY_PATH=${cudaPackages.cudatoolkit}/lib64/stubs"
(lib.cmakeBool "OPENMM_BUILD_AMOEBA_CUDA_LIB" true)
(lib.cmakeBool "OPENMM_BUILD_CUDA_LIB" true)
(lib.cmakeBool "OPENMM_BUILD_DRUDE_CUDA_LIB" true)
(lib.cmakeBool "OPENMM_BUILD_RPMD_CUDA_LIB" true)
];
postInstall = lib.strings.optionalString enablePython ''
@ -106,15 +123,13 @@ stdenv.mkDerivation (finalAttrs: {
${python3Packages.python.pythonOnBuildForHost.interpreter} -m installer --prefix $out dist/*.whl
'';
postFixup = ''
for lib in $out/lib/plugins/*CUDA.so $out/lib/plugins/*Cuda*.so; do
addDriverRunpath "$lib"
done
'';
# Couldn't get CUDA to run properly in the sandbox
doCheck = !enableCuda && !enableOpencl;
passthru = {
updateScript = nix-update-script { };
};
meta = {
description = "Toolkit for molecular simulation using high performance GPU code";
mainProgram = "TestReferenceHarmonicBondForce";

View file

@ -3,7 +3,7 @@
stdenvNoCC,
fetchFromGitHub,
nodejs,
pnpm_9,
pnpm_11,
fetchPnpmDeps,
pnpmConfigHook,
makeWrapper,
@ -24,15 +24,15 @@ stdenvNoCC.mkDerivation (finalAttrs: {
pnpmDeps = fetchPnpmDeps {
inherit (finalAttrs) pname version src;
pnpm = pnpm_9;
fetcherVersion = 3;
hash = "sha256-9s2kdvd7svK4hofnD66HkDc86WTQeayfF5y7L2dmjNg=";
pnpm = pnpm_11;
fetcherVersion = 4;
hash = "sha256-p44ctVCA3d1CXoq+zzhswVqhScF23ZhvpLUVVcrgQlM=";
};
nativeBuildInputs = [
nodejs
pnpmConfigHook
pnpm_9
pnpm_11
makeWrapper
installShellFiles
];

View file

@ -7,16 +7,16 @@
buildGoModule rec {
pname = "packer";
version = "1.15.3";
version = "1.15.4";
src = fetchFromGitHub {
owner = "hashicorp";
repo = "packer";
rev = "v${version}";
hash = "sha256-5B/PUVJMpc/9JEk1O6rYTswRuIXweeF2xMVCA/W6Md8=";
hash = "sha256-mhHES+/FCvVBBQm1qDQeH6WY2c9hIV7N3iFBCqJqJLw=";
};
vendorHash = "sha256-9aba6LnTjVmY3UgF9YyI9GoleCglTCU83QmHNPI3T2U=";
vendorHash = "sha256-HMaT1TZ2lHcKiKpZLZdRkmePb6SWV+z6QbS2q2rR/cY=";
subPackages = [ "." ];

View file

@ -27,13 +27,13 @@ assert systemdSupport -> dbusSupport;
stdenv.mkDerivation (finalAttrs: {
pname = "pcsc-tools";
version = "1.7.4";
version = "1.7.5";
src = fetchFromGitHub {
owner = "LudovicRousseau";
repo = "pcsc-tools";
tag = finalAttrs.version;
hash = "sha256-LSu+s/XcO4wM3Yvc1G/70ak+4KW+wKQ9dRm9Fdm+NsE=";
hash = "sha256-xakJwBzsZfqSLZ2wwwQoWtNIC82zOwOtm5CEVx4d+q4=";
};
configureFlags = [

View file

@ -82,7 +82,7 @@ buildGoModule {
description = "Selfhosted TCP/HTTP tunnel, ngrok alternative, written in Go";
homepage = "https://github.com/pgrok/pgrok";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ marie ];
maintainers = with lib.maintainers; [ tbutter ];
mainProgram = "pgrok";
};
}

View file

@ -18,6 +18,7 @@
libnotify,
libxkbcommon,
libgbm,
libGL,
nspr,
nss,
openssl,
@ -122,9 +123,17 @@ stdenv.mkDerivation rec {
runHook postInstall
'';
#--use-gl=egl for it to use hardware rendering it seems. Otherwise there are terrible framerates
preFixup = ''
gappsWrapperArgs+=(--add-flags "--use-gl=egl")
patchelf --add-needed libGL.so.1 \
--set-rpath "${
lib.makeLibraryPath [
libGL
]
}" \
$out/bin/Plasticity
rm "$out/lib/Plasticity/libvulkan.so.1"
ln -s -t "$out/lib/Plasticity" "${lib.getLib vulkan-loader}/lib/libvulkan.so.1"
'';
meta = {

View file

@ -14,7 +14,7 @@
libzip,
lua5_4,
luajit,
mbedtls,
mbedtls_4,
pcre2,
sdl3,
sdl3-image,
@ -26,7 +26,7 @@
stdenv.mkDerivation (finalAttrs: {
pname = "pragtical";
version = "3.11.2";
pluginManagerRev = "v1.5.1";
pluginManagerRev = "v1.5.2";
linenoiseRev = "e78e236c8d85c078fdd9fc4e1f08716058aa1a42";
src = fetchFromGitHub {
@ -47,14 +47,12 @@ stdenv.mkDerivation (finalAttrs: {
--replace-fail 'revision = master' 'revision = ${finalAttrs.linenoiseRev}'
${lib.getExe meson} subprojects download \
colors linenoise plugins ppm widget mbedtls
# TODO: remove mbedtls from list once ppm supports mbedtls_4
# See https://github.com/pragtical/plugin-manager/issues/11
colors linenoise plugins ppm widget
find subprojects -type d -name .git -prune -execdir rm -r {} +
'';
hash = "sha256-6S4hnmSsejLr7IiZ4mtHT5ImBsVlyKFtLx9PBgv6b90=";
hash = "sha256-OkvtPH8XiF3nkZ66PnKm+++NWWDK1ypGmjiZYGOiIe8=";
};
strictDeps = true;
@ -75,7 +73,7 @@ stdenv.mkDerivation (finalAttrs: {
libzip
lua5_4
luajit
mbedtls
mbedtls_4
pcre2
sdl3
sdl3-image

View file

@ -6,23 +6,25 @@
}:
buildGoModule (finalAttrs: {
pname = "prometheus-qbittorrent-exporter";
version = "1.13.0";
version = "2.0.1";
src = fetchFromGitHub {
owner = "martabal";
repo = "qbittorrent-exporter";
tag = "v${finalAttrs.version}";
hash = "sha256-ivHTGj2+6c23KW5aT5a8NFzUxV13u0y9UnHttZYTkuA=";
hash = "sha256-bVfYDIT3FMCFs/p+fFwm+xKiqbffPJ26Z2KFmBlqMjg=";
};
sourceRoot = "${finalAttrs.src.name}/src";
vendorHash = "sha256-FHKt2QpvianVVbAJUcaou/+Ok69a8NbkM7ymVgxUi0I=";
vendorHash = "sha256-vw4uwQt/PI8yl81NC3wAdgCiPacg/Pmv2MNlnR9Y/v0=";
ldflags = [
"-s"
"-X 'qbit-exp/app.version=v${finalAttrs.version}'"
];
# Tests create a local http server
__darwinAllowLocalNetworking = true;
passthru.updateScript = nix-update-script { };
meta = {

View file

@ -1,27 +1,29 @@
{
lib,
buildPythonApplication,
fetchPypi,
psutil,
matplotlib,
pytest,
python3Packages,
}:
buildPythonApplication rec {
python3Packages.buildPythonApplication (finalAttrs: {
pname = "psrecord";
version = "1.2";
format = "setuptools";
version = "1.4";
pyproject = true;
src = fetchPypi {
inherit pname version;
sha256 = "5d48410e543b71e5dc4677705acc2a753db65814d3ccbdfbca8d5d3a09b053b1";
inherit (finalAttrs) pname version;
sha256 = "sha256-WXcYVIi1ZwI5xziVGcqEy5BN3fEQH/825EWJjYcUVLE=";
};
propagatedBuildInputs = [
build-system = with python3Packages; [
setuptools
setuptools-scm
];
propagatedBuildInputs = with python3Packages; [
psutil
matplotlib
];
nativeCheckInputs = [
nativeCheckInputs = with python3Packages; [
pytest
];
@ -38,4 +40,4 @@ buildPythonApplication rec {
maintainers = with lib.maintainers; [ johnazoidberg ];
mainProgram = "psrecord";
};
}
})

View file

@ -1,9 +1,10 @@
{
fetchFromGitHub,
stdenv,
testers,
validatePkgConfig,
lib,
qt6,
...
}:
stdenv.mkDerivation (finalAttrs: {
pname = "qtwebapp";
@ -15,6 +16,8 @@ stdenv.mkDerivation (finalAttrs: {
hash = "sha256-RbFgz2ed1eEVy44LX+milP4hPSeiabakU3TMvHYR7TU=";
};
__structuredAttrs = true;
sourceRoot = "source/QtWebApp";
postPatch = ''
@ -29,19 +32,47 @@ stdenv.mkDerivation (finalAttrs: {
nativeBuildInputs = [
qt6.qmake
qt6.wrapQtAppsHook
validatePkgConfig
];
buildInputs = [
propagatedBuildInputs = [
# For libs in the pkg-config, they must be
# propagated so that packages that depend on
# it can properly use it.
qt6.qtbase
qt6.qt5compat
];
qmakeFlags = [ "QtWebApp.pro" ];
pkgConfigFile = ./pkg-config.in;
postInstall = ''
mkdir -p "$out/lib/pkgconfig"
cp "$pkgConfigFile" "$out/lib/pkgconfig/QtWebApp.pc"
substituteInPlace "$out/lib/pkgconfig/QtWebApp.pc" \
--subst-var out \
--subst-var version
mkdir -p "$out/include/QtWebApp/httpserver"
cp httpserver/*.h "$out/include/QtWebApp/httpserver"
mkdir -p "$out/include/QtWebApp/logging"
cp logging/*.h "$out/include/QtWebApp/logging"
mkdir -p "$out/include/QtWebApp/templateengine"
cp templateengine/*.h "$out/include/QtWebApp/templateengine"
'';
passthru.tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
meta = {
maintainers = with lib.maintainers; [ xddxdd ];
description = "HTTP server library in C++, inspired by Java Servlets";
homepage = "https://stefanfrings.de/qtwebapp/index-en.html";
license = lib.licenses.lgpl3Plus;
pkgConfigModules = [
"QtWebApp"
];
};
})

View file

@ -0,0 +1,14 @@
prefix=@out@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir_http=${prefix}/include/QtWebApp/httpserver
includedir_logging=${prefix}/include/QtWebApp/logging
includedir_template=${prefix}/include/QtWebApp/templateengine
Name: QtWebApp
Description: HTTP server and utility library in C++
Version: @version@
Requires: Qt6Network Qt6Core5Compat
Libs: -L${libdir} -lQtWebApp
Cflags: -I${includedir_http} -I${includedir_logging} -I${includedir_template}

View file

@ -8,11 +8,11 @@
stdenv.mkDerivation (finalAttrs: {
pname = "quarkus-cli";
version = "3.35.3";
version = "3.36.1";
src = fetchurl {
url = "https://github.com/quarkusio/quarkus/releases/download/${finalAttrs.version}/quarkus-cli-${finalAttrs.version}.tar.gz";
hash = "sha256-fxwAYpQimDmctRCfPqi11RzK2/95DeSh+ULaC9jrHQo=";
hash = "sha256-fhGWH8ksB0JzhQL8EWkKCFA+8EpY7EMsgnTMHqGFbQ0=";
};
nativeBuildInputs = [ makeWrapper ];

View file

@ -14,16 +14,16 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "rattler-build";
version = "0.65.0";
version = "0.65.1";
src = fetchFromGitHub {
owner = "prefix-dev";
repo = "rattler-build";
tag = "v${finalAttrs.version}";
hash = "sha256-RhFaNron6gsRSTwBsncKlaCwQWCp5Ks7XYN6/DfKjQA=";
hash = "sha256-e9Alo7ZiPUhpupl46WDiHUDSAe9N8T+3eBy83o+Hf1g=";
};
cargoHash = "sha256-FfiHTXTVjLiyUG05wmz2jnIhW0Z/544Thg8Y7WgUHFE=";
cargoHash = "sha256-eUG2/jNNLF0OJEQ9griNbl3UxY9CwWOjsdM5gZDcHrI=";
doCheck = false; # test requires network access

View file

@ -8,7 +8,7 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "rgx";
version = "0.12.6";
version = "0.14.1";
__structuredAttrs = true;
@ -16,10 +16,10 @@ rustPlatform.buildRustPackage (finalAttrs: {
owner = "brevity1swos";
repo = "rgx";
tag = "v${finalAttrs.version}";
hash = "sha256-YdbuyVhqu1LUaHecF1iFS62/qcW9IgXPlsEoWpNdrEQ=";
hash = "sha256-4ubPvcxRjwIbPsnxEu6QXPflPUJRnij8WIKeFT+Jxkg=";
};
cargoHash = "sha256-ILq0oB+Xq4agQMWqGLV0LC4NlMkUMVFppLJ+FJpsTRM=";
cargoHash = "sha256-u0qCt/XwCayAOKDwD+nQiy41F/x6HORZmqzgpTsBdzM=";
buildInputs = [ pcre2 ];

View file

@ -7,16 +7,16 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "routinator";
version = "0.15.1";
version = "0.15.2";
src = fetchFromGitHub {
owner = "NLnetLabs";
repo = "routinator";
rev = "v${finalAttrs.version}";
hash = "sha256-tgDhIM8Dw4k/ocXa3U1xqS/TDmqNbjnNzIyCxEmu294=";
hash = "sha256-y/L9l++uB627lEHK+mASNwLohqWk+R0FUNYMKKNg38A=";
};
cargoHash = "sha256-XOy8sm6nzmihFYsgLcusoYKwgTvx0qX8o8XWV4EMXZ8=";
cargoHash = "sha256-rDFwfRXd8oMNh8iOPEWM1eADFQjys0GwPVr2r5hLW4Y=";
meta = {
description = "RPKI Validator written in Rust";

View file

@ -2,27 +2,37 @@
lib,
python3Packages,
fetchPypi,
versionCheckHook,
}:
python3Packages.buildPythonApplication (finalAttrs: {
pname = "rshell";
version = "0.0.36";
format = "setuptools";
pyproject = true;
__structuredAttrs = true;
src = fetchPypi {
inherit (finalAttrs) pname version;
hash = "sha256-SmbYNSB0eVUOWdDdPoMAPQTE7KeKTkklD4h+0t1LC/U=";
};
build-system = [
python3Packages.setuptools
];
dependencies = with python3Packages; [
pyserial
pyudev
];
nativeCheckInputs = [ versionCheckHook ];
meta = {
homepage = "https://github.com/dhylands/rshell";
description = "Remote Shell for MicroPython";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ c0deaddict ];
mainProgram = "rshell";
};
})

View file

@ -1,64 +0,0 @@
diff --git a/packages/server/src/api.js b/packages/server/src/api.js
index bd43842..71ce7c9 100644
--- a/packages/server/src/api.js
+++ b/packages/server/src/api.js
@@ -105,7 +105,7 @@ module.exports = new class Api {
}
// If not then it's possible the default image is not quite the correct aspect ratio
- const buffer = FileInfo.create(`${config.previewDirectory}/default.jpg`).toBuffer();
+ const buffer = FileInfo.create('NIX_OUT_PLACEHOLDER/lib/node_modules/scanservjs-api/data/preview/default.jpg').toBuffer();
try {
// We need to know the correct aspect ratio from the device
diff --git a/packages/server/src/application.js b/packages/server/src/application.js
index 2771036..0c2a4c0 100644
--- a/packages/server/src/application.js
+++ b/packages/server/src/application.js
@@ -26,7 +26,7 @@ module.exports = new class Application {
userOptions() {
if (this._userOptions === null) {
- this._userOptions = new UserOptions('../../config/config.local.js');
+ this._userOptions = new UserOptions(process.env.NIX_SCANSERVJS_CONFIG_PATH);
}
return this._userOptions;
}
diff --git a/packages/server/src/classes/user-options.js b/packages/server/src/classes/user-options.js
index f129e3c..c71e754 100644
--- a/packages/server/src/classes/user-options.js
+++ b/packages/server/src/classes/user-options.js
@@ -4,7 +4,7 @@ const path = require('path');
module.exports = class UserOptions {
constructor(localConfigPath) {
if (localConfigPath) {
- const localPath = path.join(__dirname, localConfigPath);
+ const localPath = localConfigPath;
if (fs.existsSync(localPath)) {
this.local = require(localPath);
}
diff --git a/packages/server/src/configure.js b/packages/server/src/configure.js
index c9e5ed8..484949c 100644
--- a/packages/server/src/configure.js
+++ b/packages/server/src/configure.js
@@ -71,6 +71,7 @@ function initialize(rootPath) {
try {
fs.mkdirSync(config.outputDirectory, { recursive: true });
+ fs.mkdirSync(config.previewDirectory, { recursive: true });
fs.mkdirSync(config.tempDirectory, { recursive: true });
} catch (exception) {
log.warn(`Error ensuring output and temp directories exist: ${exception}`);
diff --git a/packages/server/src/server.js b/packages/server/src/server.js
index e1a9fb0..3d58d37 100644
--- a/packages/server/src/server.js
+++ b/packages/server/src/server.js
@@ -5,7 +5,7 @@ const configure = require('./configure');
const config = application.config();
const app = express();
-app.use(express.static('client'));
+app.use(express.static('@client@'));
configure(app);

View file

@ -0,0 +1,47 @@
diff --git a/app-server/src/application.js b/app-server/src/application.js
index a2c065f..2d594bf 100644
--- a/app-server/src/application.js
+++ b/app-server/src/application.js
@@ -26,7 +26,7 @@ module.exports = new class Application {
userOptions() {
if (this._userOptions === null) {
- this._userOptions = new UserOptions('../../config/config.local.js');
+ this._userOptions = new UserOptions(process.env.NIX_SCANSERVJS_CONFIG_PATH);
}
return this._userOptions;
}
diff --git a/app-server/src/classes/user-options.js b/app-server/src/classes/user-options.js
index f129e3c..c71e754 100644
--- a/app-server/src/classes/user-options.js
+++ b/app-server/src/classes/user-options.js
@@ -4,7 +4,7 @@ const path = require('path');
module.exports = class UserOptions {
constructor(localConfigPath) {
if (localConfigPath) {
- const localPath = path.join(__dirname, localConfigPath);
+ const localPath = localConfigPath;
if (fs.existsSync(localPath)) {
this.local = require(localPath);
}
diff --git a/app-server/src/express-configurer.js b/app-server/src/express-configurer.js
index 945dae2..1b456cc 100644
--- a/app-server/src/express-configurer.js
+++ b/app-server/src/express-configurer.js
@@ -166,6 +166,7 @@ module.exports = class ExpressConfigurer {
try {
fs.mkdirSync(config.outputDirectory, { recursive: true });
+ fs.mkdirSync(config.previewDirectory, { recursive: true });
fs.mkdirSync(config.thumbnailDirectory, { recursive: true });
fs.mkdirSync(config.tempDirectory, { recursive: true });
} catch (exception) {
@@ -220,7 +221,7 @@ module.exports = class ExpressConfigurer {
* @returns {ExpressConfigurer}
*/
statics() {
- this.app.use(express.static('client'));
+ this.app.use(express.static('@client@'));
return this;
}

View file

@ -3,6 +3,7 @@
fetchFromGitHub,
buildNpmPackage,
nodejs,
nixosTests,
}:
buildNpmPackage (finalAttrs: {
@ -18,13 +19,42 @@ buildNpmPackage (finalAttrs: {
npmDepsHash = "sha256-HIWT09G8gqSFt9CIjsjJaDRnj2GO0G6JOGeI0p4/1vw=";
postInstall = ''
mkdir $out/bin
patches = [
./nix-compatibility.patch
];
postBuild = ''
# Install runtime dependencies
npm install \
--prefix ./dist \
--offline \
--production \
--ignore-scripts
'';
installPhase = ''
runHook preInstall
rm -rf $out/lib
mkdir -p $out/lib
cp -r dist/* $out/lib
substituteInPlace "$out/lib/server/express-configurer.js" \
--replace-fail "@client@" "$out/lib/client"
mkdir -p $out/bin
makeWrapper ${lib.getExe nodejs} $out/bin/scanservjs \
--set NODE_ENV production \
--add-flags "'$out/lib/node_modules/scanservjs/app-server/src/server.js'"
--add-flags "$out/lib/server/server.js"
runHook postInstall
'';
passthru = {
tests.smoke-test = nixosTests.scanservjs;
};
meta = {
description = "SANE scanner nodejs web ui";
longDescription = "scanservjs is a simple web-based UI for SANE which allows you to share a scanner on a network without the need for drivers or complicated installation.";

View file

@ -12,24 +12,28 @@
ffmpeg,
glib,
libpulseaudio,
versionCheckHook,
nix-update-script,
pipewire,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "songrec";
version = "0.6.7";
version = "0.7.3";
src = fetchFromGitHub {
owner = "marin-m";
repo = "songrec";
rev = finalAttrs.version;
hash = "sha256-lCwFMBQ6IimNtXYMfTnFOpwOO2qbwijOEZ+oMsQKAP0=";
tag = finalAttrs.version;
hash = "sha256-6DT5KY6Y3CPTFLNG+EostAlMgZ35SLv8r9EXtRadC2U=";
};
cargoHash = "sha256-BhDFGkvY6c8XbhJpFX1w8CSXK9IY/HiysNoooytFT9I=";
cargoHash = "sha256-9R7HwTwjeCBIxX2xHs++9Zl0SMRmHPHDD1OHNa4q+jI=";
nativeBuildInputs = [
pkg-config
wrapGAppsHook4
rustPlatform.bindgenHook
];
buildInputs = [
@ -40,6 +44,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
libadwaita
libpulseaudio
libsoup_3
pipewire
];
preFixup = ''
@ -52,12 +57,21 @@ rustPlatform.buildRustPackage (finalAttrs: {
mv packaging/rootfs/usr/share $out/share
'';
doInstallCheck = true;
nativeInstallCheckInputs = [ versionCheckHook ];
passthru.updateScript = nix-update-script { };
meta = {
description = "Open-source Shazam client for Linux, written in Rust";
homepage = "https://github.com/marin-m/SongRec";
changelog = "https://github.com/marin-m/SongRec/releases/tag/${finalAttrs.src.tag}";
license = lib.licenses.gpl3Plus;
platforms = lib.platforms.linux;
maintainers = with lib.maintainers; [ tcbravo ];
maintainers = with lib.maintainers; [
tcbravo
tomasrivera
];
mainProgram = "songrec";
};
})

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