Merge staging-next into staging

This commit is contained in:
nixpkgs-ci[bot]
2025-12-20 18:06:06 +00:00
committed by GitHub
121 changed files with 2041 additions and 3009 deletions
+1 -1
View File
@@ -263,7 +263,7 @@
- any-glob-to-any-file:
- nixos/modules/services/cluster/rancher/default.nix
- nixos/modules/services/cluster/rancher/k3s.nix
- nixos/tests/k3s/**/*
- nixos/tests/rancher/**/*
- pkgs/applications/networking/cluster/k3s/**/*
"6.topic: kernel":
+1
View File
@@ -439,6 +439,7 @@ pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @emilylange
/pkgs/build-support/node/prefetch-npm-deps @winterqt
/doc/languages-frameworks/javascript.section.md @winterqt
/pkgs/development/tools/pnpm @Scrumplex @gepbird
/pkgs/build-support/node/fetch-pnpm-deps @Scrumplex @gepbird
# OCaml
/pkgs/build-support/ocaml @ulrikstrid
-6
View File
@@ -1185,12 +1185,6 @@
"module-services-gitlab-maintenance-rake": [
"index.html#module-services-gitlab-maintenance-rake"
],
"module-services-gitlab-runner": [
"index.html#module-services-gitlab-runner"
],
"ex-gitlab-runner-podman": [
"index.html#ex-gitlab-runner-podman"
],
"module-forgejo": [
"index.html#module-forgejo"
],
+1 -1
View File
@@ -502,7 +502,7 @@
./services/continuous-integration/buildkite-agents.nix
./services/continuous-integration/gitea-actions-runner.nix
./services/continuous-integration/github-runners.nix
./services/continuous-integration/gitlab-runner/runner.nix
./services/continuous-integration/gitlab-runner.nix
./services/continuous-integration/gocd-agent/default.nix
./services/continuous-integration/gocd-server/default.nix
./services/continuous-integration/hercules-ci-agent/default.nix
-113
View File
@@ -10,7 +10,6 @@ configure a webserver to proxy HTTP requests to the socket.
For instance, the following configuration could be used to use nginx as
frontend proxy:
```nix
{
services.nginx = {
@@ -41,7 +40,6 @@ The default state dir is `/var/gitlab/state`. This is where
all data like the repositories and uploads will be stored.
A basic configuration with some custom settings could look like this:
```nix
{
services.gitlab = {
@@ -106,7 +104,6 @@ the [services.gitlab.backup.startAt](#opt-services.gitlab.backup.startAt)
option to configure regular backups.
To run a manual backup, start the `gitlab-backup` service:
```ShellSession
$ systemctl start gitlab-backup.service
```
@@ -119,116 +116,6 @@ will have to run the command as the user that you configured to run
GitLab with.
A list of all available rake tasks can be obtained by running:
```ShellSession
$ sudo -u git -H gitlab-rake -T
```
## Runner {#module-services-gitlab-runner}
GitLab Runner is a CI runner which is an executable which you can host yourself.
A Gitlab pipeline runs operations over a Gitlab Runner. These can include
building an executable, running a test suite, pushing a docker image, etc. The
Gitlab Runner receives jobs from Gitlab which it then dispatches to the
configured executors
([`docker` (`podman`), or `shell` or `kubernetes`](https://docs.gitlab.com/runner/executors)).
The
[services.gitlab-runner.services](https://search.nixos.org/options?query=services.gitlab-runner.services)
documents a number of typical setups to configure multiple runners with
different executors.
The [below example](#ex-gitlab-runner-podman) gives a **more elaborate** example how to
configure a Gitlab Runner with caching and reasonably good security practices.
::: {#ex-gitlab-runner-podman .example}
## Example: Gitlab Runner with `podman` and Nix Store Caching
The [VM tested `podman-runner`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/continuous-integration/gitlab-runner/runner.nix)
(a NixOS module for reuse) configures an advanced Gitlab runner with the following features:
- The executor is `podman` which gives you better additional safety than
`docker`. That means every job is run in a `podman` container.
- The following container **images** are built with Nix:
**Container Images for Gitlab Jobs**:
- `local/alpine`: An image based on Alpine with a Nix installation
(attribute `jobImages.alpine`).
- `local/ubuntu`: An image based on Ubuntu with a Nix installation
(attribute `jobImages.ubuntu`).
- `local/nix`: An image based on Nix which only comes with `nix`
installed (attribute `jobImages.nix`).
**Images for VM Setup**:
- `local/nix-daemon-image`: An image with a Nix daemon which is
used to share the `/nix/store` across jobs (variable `nixDaemonImage`) setup with some essentials derivations `bootstrapPkgs`.
- `local/podman-daemon-image`: An image with `podman` running as a daemon which is
used to run `podman` inside the above job containers images
(variable `podmanDaemonImage`).
- Every job container runs in a `podman` container instance based by default on
`jobImage.ubuntu`. A pipeline job can override this with `image: local/alpine`.
- Each job container will have the `/nix/store` mounted from the container
`nix-daemon-container` (see registration flags
`--docker-volumes-from "nix-daemon-container:ro"`).
The `nix-daemon-container` is a single container instance of a
`nixDaemonImage`. This enables caching of `/nix/store` paths across all jobs
in **all** runners. This makes **the host VM's `/nix/store` independent of the
Nix store used in the jobs**, which is good.
::: {.note}
**Security:** If you don't want this you need multiple `nixDaemonImage`
containers for each registered runner (`gitlab-runner.services.<name>`).
:::
- Each job container will have the `/run/podman/podman.sock` socket mounted from the
`podman-daemon-container`.
The `podman-daemon-container` is a single container of a `podmanDaemonImage` which runs
`podman` as a daemon. Job containers can use this daemon to spawn nested containers as well (podman-in-podman).
**Keep in mind that `bind` mounts are local to the `podman-daemon-container`**
and can be be worked around with a `podman volume create <vol>` and manual copy-to/copy-from this volume `<vol>`.
If you only need to build containers you don't need this feature (`podman-daemon-container`), see below point.
Container configuration files (`auxRootFiles`) are copied to all containers to
ensure `podman` works consistently inside the job containers.
- The job containers do **not** mount the `podman` socket from the host (NixOS
VM) mounted for security reasons.
::: {.note}
Building container images with `buildah` (stripped
`podman` for building images) inside a job which runs `jobImage.alpine`
is still possible.
:::
- **Cleanup Disk Space**:
With this setup its really easy to clean the `nix-daemon-container`
(e.g. if you run out of disk space), then reboot and have the runner in a clean state.
You can do the following to effectively clean everything and start with fresh volumes safely:
```bash
# Stop the Gitlab runner.
systemctl stop gitlab-runner.service
# Stop `systemd`-managed containers, such that they get not recreated
# when deleting below.
systemctl stop podman-podman-daemon-container.service \
podman-nix-daemon-container.service \
podman-nix-container.service \
podman-alpine-container.service \
podman-ubuntu-container.service || true
podman container rm -f --all
podman image rm -f --all
podman volumes rm -f --all
reboot
# Systemd will restart all containers and create volumes etc.
```
:::
+15 -3
View File
@@ -89,6 +89,18 @@ in
'';
};
user = lib.mkOption {
type = lib.types.str;
default = "photoprism";
description = "User under which photoprism runs.";
};
group = lib.mkOption {
type = lib.types.str;
default = "photoprism";
description = "Group under which photoprism runs.";
};
package = lib.mkPackageOption pkgs "photoprism" { };
settings = lib.mkOption {
@@ -110,11 +122,11 @@ in
serviceConfig = {
Restart = "on-failure";
User = "photoprism";
Group = "photoprism";
User = cfg.user;
Group = cfg.group;
DynamicUser = true;
StateDirectory = "photoprism";
WorkingDirectory = "/var/lib/photoprism";
WorkingDirectory = cfg.storagePath;
RuntimeDirectory = "photoprism";
ReadWritePaths = [
cfg.originalsPath
+15 -5
View File
@@ -643,9 +643,7 @@ in
gitdaemon = runTest ./gitdaemon.nix;
gitea = handleTest ./gitea.nix { giteaPackage = pkgs.gitea; };
github-runner = runTest ./github-runner.nix;
gitlab = import ./gitlab {
inherit runTest;
};
gitlab = runTest ./gitlab.nix;
gitolite = runTest ./gitolite.nix;
gitolite-fcgiwrap = runTest ./gitolite-fcgiwrap.nix;
glance = runTest ./glance.nix;
@@ -802,7 +800,11 @@ in
jitsi-meet = runTest ./jitsi-meet.nix;
jool = import ./jool.nix { inherit pkgs runTest; };
jotta-cli = runTest ./jotta-cli.nix;
k3s = handleTest ./k3s { };
k3s = import ./rancher {
inherit pkgs runTest;
inherit (pkgs) lib;
rancherDistro = "k3s";
};
kafka = handleTest ./kafka { };
kaidan = runTest ./kaidan;
kanboard = runTest ./web-apps/kanboard.nix;
@@ -1343,7 +1345,15 @@ in
restic-rest-server = runTest ./restic-rest-server.nix;
retroarch = runTest ./retroarch.nix;
ringboard = runTest ./ringboard.nix;
rke2 = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./rke2 { };
rke2 = import ./rancher {
inherit pkgs;
inherit (pkgs) lib;
runTest = runTestOn [
"aarch64-linux"
"x86_64-linux"
];
rancherDistro = "rke2";
};
rkvm = handleTest ./rkvm { };
rmfakecloud = runTest ./rmfakecloud.nix;
robustirc-bridge = runTest ./robustirc-bridge.nix;
@@ -7,12 +7,12 @@
# - Opening and closing issues.
# - Downloading repository archives as tar.gz and tar.bz2
# Run with
# [nixpkgs]$ nix-build -A nixosTests.gitlab.gitlab
# [nixpkgs]$ nix-build -A nixosTests.gitlab
{ pkgs, lib, ... }:
let
inherit (import ../ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
initialRootPassword = "notproduction";
rootProjectId = "2";
@@ -37,7 +37,7 @@ in
gitlab =
{ ... }:
{
imports = [ ../common/user-account.nix ];
imports = [ common/user-account.nix ];
environment.systemPackages = with pkgs; [ git ];
-5
View File
@@ -1,5 +0,0 @@
{ runTest }:
{
gitlab = runTest ./gitlab.nix;
runner = runTest ./runner.nix;
}
-178
View File
@@ -1,178 +0,0 @@
# This test runs a gitlab-runner and performs the following tests in
# two machines `gitlab` and `gitlab-runner`:
# - Create runners in the `gitlab` machine for all runners in `./runner`.
# - Inject the runner tokens into the `gitlab-runner.service` (machine `gitlab-runner`)
# which runs all runners:
# - Shell runner in `./runner/shell-runner`.
# - Start the `gitlab-runner.service`.
# - Check that all runners in `gitlab` are `active`.
#
# Run with
# [nixpkgs]$ nix-build -A nixosTests.gitlab.runner
{
pkgs,
lib,
...
}:
let
initialRootPassword = "notproduction";
runnerTokenDir = "/run/secrets/gitlab-runner";
runnerConfigs = {
# The Gitlab runner where each job runs
# on the host (not containerized and very insecure).
shell = {
desc = "Shell runner (host NixOS shell, host Nix store)";
name = "shell";
tokenFile = "${runnerTokenDir}/token-shell.env";
};
# The Gitlab runner which uses the Docker runner (we use podman).
# Features:
# - Daemonizes the Nix store into a container.
# - All jobs run in an unprivileged container, e.g. with image
# (`local/nix`, `local/alpine`, `local/ubuntu`)
podman = {
desc = "Podman runner (containers, shared containerized Nix store)";
name = "podman";
tokenFile = "${runnerTokenDir}/token-podman.env";
};
};
in
{
name = "gitlab-runner";
meta.maintainers = with lib.maintainers; [
gabyx
];
nodes = {
gitlab-runner =
{ ... }:
{
imports = [
../common/user-account.nix
(import ./runner/shell-runner.nix {
runnerConfig = runnerConfigs.shell;
})
]
# Only enable the podman runner on x86_64
# cause of built images.
++ (lib.optional pkgs.stdenv.buildPlatform.isx86_64 (
import ./runner/podman-runner {
runnerConfig = runnerConfigs.podman;
}
));
virtualisation = {
diskSize = 10000;
};
# Define the Gitlab Runner.
services.gitlab-runner = {
enable = true;
settings = {
log_level = "info";
};
gracefulTermination = false;
};
};
gitlab =
{ config, ... }:
{
imports = [ ../common/user-account.nix ];
networking.firewall.allowedTCPPorts = [
config.services.nginx.defaultHTTPListenPort
];
environment.systemPackages = with pkgs; [ git ];
virtualisation.memorySize = 6144;
virtualisation.cores = 4;
systemd.services.gitlab.serviceConfig.Restart = lib.mkForce "no";
systemd.services.gitlab-workhorse.serviceConfig.Restart = lib.mkForce "no";
systemd.services.gitaly.serviceConfig.Restart = lib.mkForce "no";
systemd.services.gitlab-sidekiq.serviceConfig.Restart = lib.mkForce "no";
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts = {
localhost = {
locations."/".proxyPass = "http://unix:/run/gitlab/gitlab-workhorse.socket";
};
};
};
services.gitlab = {
enable = true;
databasePasswordFile = pkgs.writeText "dbPassword" "xo0daiF4";
initialRootPasswordFile = pkgs.writeText "rootPassword" initialRootPassword;
secrets = {
secretFile = pkgs.writeText "secret" "Aig5zaic";
otpFile = pkgs.writeText "otpsecret" "Riew9mue";
dbFile = pkgs.writeText "dbsecret" "we2quaeZ";
jwsFile = pkgs.runCommand "oidcKeyBase" { } "${pkgs.openssl}/bin/openssl genrsa 2048 > $out";
activeRecordPrimaryKeyFile = pkgs.writeText "arprimary" "vsaYPZjTRxcbG7W6gNr95AwBmzFUd4Eu";
activeRecordDeterministicKeyFile = pkgs.writeText "ardeterministic" "kQarv9wb2JVP7XzLTh5f6DFcMHms4nEC";
activeRecordSaltFile = pkgs.writeText "arsalt" "QkgR9CfFU3MXEWGqa7LbP24AntK5ZeYw";
};
# reduce memory usage
sidekiq.concurrency = 1;
puma.workers = 2;
};
};
};
testScript =
{ nodes, ... }:
let
authPayload = pkgs.writeText "auth.json" (
builtins.toJSON {
grant_type = "password";
username = "root";
password = initialRootPassword;
}
);
runnerTokenEnv = pkgs.writeText "runner-token.env" ''
CI_SERVER_URL=http://gitlab
CI_SERVER_TOKEN=$token
'';
createRunnerPayload = pkgs.writeText "create-runner.json" (
builtins.toJSON {
runner_type = "instance_type";
}
);
in
# python
''
# Define some globals for the python script below.
JQ_BINARY="${pkgs.jq}/bin/jq"
GITLAB_STATE_PATH="${nodes.gitlab.services.gitlab.statePath}"
RUNNER_TOKEN_ENV_FILE="${runnerTokenEnv}"
AUTH_PAYLOAD_FILE="${authPayload}"
CREATE_RUNNER_PAYLOAD_FILE="${createRunnerPayload}"
${lib.readFile ./runner_test.py}
start_all()
wait_for_services()
# Run all tests.
test_connection()
test_register_runner(name="shell", tokenFile="${runnerConfigs.shell.tokenFile}")
test_register_runner(name="podman", tokenFile="${runnerConfigs.podman.tokenFile}")
restart_gitlab_runner_service(runnerConfigs)
test_runner_registered(runnerConfigs["shell"])
test_runner_registered(runnerConfigs["podman"])
'';
}
@@ -1,442 +0,0 @@
{ runnerConfig }:
# Gitlab Runner Module
#
# This module will add a Gitlab-Runner
# configured similar to https://wiki.nixos.org/wiki/Gitlab_runner
# with a nix-daemon running in a podman container `nix-daemon-container`.
#
# - The volumes from the `nix-daemon-container` will get mounted to
# each job container which Gitlab starts, which gives them access
# to a commonly shared Nix store.
#
# - The `/nix/store` inside the job container
# (either image `alpineImage` or `ubuntuImage` or `nixImage`)
# will be read-only and nix can only store stuff into this path by using the
# `NIX_DAEMON` env. variable which lets it communicate through the
# mounted daemon socket.
# - The `bootstrapPkgs` derivation is copied into the job containers
# but without the Nix store paths cause they get provided by the
# `nix-daemon-store` volume.
# I cannot denote these volumes because they overmount the
# shit which is in the image.
# TODO: make a systemd service which starts before
# that and creates some volumes and inits these from the image.
#
# - The `podman-daemon-socket` volume gets mounted to the job container
# enabling it to use `podman`.
# Note: The job container instance is not using the system `podman` running in NixOS.
# Its a dedicated podman service `podmanDaemonContainer`
# running as `--privileged`
# [non-rootless container](https://rootlesscontaine.rs/#what-are-rootless-containers-and-what-are-not).
# (TODO: This podman daemon instance could be maybe run as rootless
# container under a user `ci` and a separated Gitlab Runner could
# run over this socket, effectively run only rootless containers.)
#
# - There is also a job runner prebuild script which is started on every job.
# See `scripts/prebuild.nix` to setup some missing stuff.
#
# Debugging on the VM:
#
# - You can use `journalclt -u gitlab-runner.service`.
#
# - To run a job container use:
# ```bash
# podman run --rm -it
# --volumes-from 'nix-daemon-container'
# -v "podman-daemon-socket:/run/podman"
# "local/alpine" \
# bash -c "export CI_PIPkELINE_ID=123456 && gitlab-runner-prebuild-script; echo hello"
# ```
{
lib,
pkgs,
...
}:
let
nixRepo = pkgs.fetchFromGitHub {
owner = "NixOS";
repo = "nix";
rev = "2.32.4";
hash = "sha256-8QYnRyGOTm3h/Dp8I6HCmQzlO7C009Odqyp28pTWgcY=";
};
# Either we use a Nix as the base image or Alpine.
imageNames = {
default = imageNames.alpine;
alpine = "local/alpine";
nix = "local/nix";
ubuntu = "local/ubuntu";
all = with imageNames; [
alpine
nix
ubuntu
];
};
noPruneLabels = {
no-prune = "true";
};
# This derivation will contain a folder `/etc`
files = pkgs.callPackage ./files { };
preBuildScript = pkgs.callPackage ./scripts/prebuild.nix { };
# These derivations are Linked into the job images root dir.
bootstrapPkgs = [
pkgs.nix
# Runtime dependencies of nix.
pkgs.gnutar
pkgs.gzip
pkgs.openssh
pkgs.xz
pkgs.cacert
# Other stuff.
(lib.hiPrio pkgs.coreutils)
(lib.hiPrio pkgs.findutils)
pkgs.openssh
pkgs.bashInteractive
(lib.hiPrio pkgs.git)
pkgs.cachix
pkgs.just
pkgs.podman # For nested containers.
preBuildScript
files.containers
files.nixConfig
];
# All these packages are added to the Nix daemon.
nixStorePkgs = bootstrapPkgs ++ [
# These files
files.basicRoot
files.fakeNixpkgs
];
toEnvList = envs: lib.mapAttrsToList (k: v: "${k}=${v}") envs;
# This is the Nix base image.
nixImageBase = pkgs.callPackage (import (nixRepo + "/docker.nix")) {
name = "local/nix-base";
tag = "latest";
bundleNixpkgs = false;
maxLayers = 2;
# You can add here a user with uid,gid,uname,gname etc.
# We are using root.
extraPkgs = nixStorePkgs;
nixConf = {
cores = "0";
experimental-features = [
"nix-command"
"flakes"
];
};
};
# This is the daemon image which provides the store
# as volumes.
nixDaemonImage = pkgs.dockerTools.buildLayeredImage {
fromImage = nixImageBase;
name = "local/nix-daemon";
tag = "latest";
config = {
Volumes = {
"/nix/store" = { };
"/nix/var/nix/db" = { };
"/nix/var/nix/daemon-socket" = { };
};
Labels = noPruneLabels;
};
maxLayers = 4;
};
# This is the podman daemon image which enables
# a job image to use `podman` internally.
podmanDaemonImage =
let
# Update with:
# ```shell
# nix run "github:nixos/nixpkgs/nixos-unstable#nix-prefetch-docker" -- \
# --image-name quay.io/podman/stable --image-tag v5.6.0
# ```
base = pkgs.dockerTools.pullImage {
imageName = "quay.io/podman/stable";
imageDigest = "sha256:7c9381b9af167cf2218831c3af3135856c99f488b543b78435c8f18e19ad739a";
hash = "sha256-pXXCu13fB/RN9qx8iLhE5Kko6glTrFrRhR7fo2OS7V0=";
finalImageName = "quay.io/podman/stable";
finalImageTag = "v5.6.0";
};
in
pkgs.dockerTools.buildLayeredImage {
fromImage = base;
name = "local/podman-daemon";
tag = "latest";
config = {
Labels = noPruneLabels;
};
};
jobImages =
let
extraCommands = ''
set -eu
# Set missing Nix directories.
mkdir -p -m 0755 nix/var/log/nix/drvs
mkdir -p -m 0755 nix/var/nix/{gcroots,profiles,temproots,userpool}
mkdir -p -m 1777 nix/var/nix/{gcroots,profiles}/per-user
mkdir -p -m 0755 nix/var/nix/profiles/per-user/root
# Need a HOME.
mkdir -vp root
mkdir -p -m 0700 root/.nix-defexpr
'';
in
{
# The Nix image.
# Similar to https://github.com/nix-community/docker-nixpkgs/blob/main/images/nix/default.nix.
nix = pkgs.dockerTools.buildLayeredImage {
name = imageNames.nix;
tag = "latest";
extraCommands = extraCommands + ''
set -eu
# For `/usr/bin/env`.
mkdir -p usr && ln -s ../bin usr/bin
'';
contents = bootstrapPkgs ++ [ files.basicRoot ];
# No store paths are copied into. We provide them by mounting the
# /nix/store.
includeStorePaths = false;
config = {
Labels = noPruneLabels;
Env = toEnvList envs.nix;
};
maxLayers = 2;
};
# This is the analog image to `local/nix` but Alpine based.
alpine =
let
# Update with:
# ```shell
# nix run "github:nixos/nixpkgs/nixos-unstable#nix-prefetch-docker" -- --image-name alpine --image-tag latest
# ```
alpineBase = pkgs.dockerTools.pullImage {
imageName = "alpine";
imageDigest = "sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d";
sha256 = "0gf7wbjp37zbni3pz8vdgq1mss6mz69wynms0gqhq7lsxfmg9xj9";
finalImageName = "alpine";
finalImageTag = "latest";
};
in
(pkgs.dockerTools.buildLayeredImage {
fromImage = alpineBase;
name = imageNames.alpine;
tag = "latest";
inherit extraCommands;
contents = bootstrapPkgs;
# No store paths are copied into. We provide them by mounting the
# /nix/store.
includeStorePaths = false;
config = {
Labels = noPruneLabels;
Env = toEnvList envs.nix;
};
# Only if `build buildLayeredImage`.
maxLayers = 3;
});
# This is the analog image to `local/nix` but Ubuntu based.
ubuntu =
let
# Update with:
# ```shell
# nix run "github:nixos/nixpkgs/nixos-unstable#nix-prefetch-docker" -- \
# --image-name ubuntu --image-tag latest
# ```
ubuntuBase = pkgs.dockerTools.pullImage {
imageName = "ubuntu";
imageDigest = "sha256:1e622c5f073b4f6bfad6632f2616c7f59ef256e96fe78bf6a595d1dc4376ac02";
hash = "sha256-aC8SgxdcMSaaU89YMr/uwE022Yqey2frmeZqr+L1xEU=";
finalImageName = "ubuntu";
finalImageTag = "latest";
};
in
(pkgs.dockerTools.buildLayeredImage {
fromImage = ubuntuBase;
name = imageNames.ubuntu;
tag = "latest";
inherit extraCommands;
contents = bootstrapPkgs;
# No store paths are copied into. We provide them by mounting the
# /nix/store.
includeStorePaths = false;
config = {
Labels = noPruneLabels;
Env = toEnvList envs.ubuntu;
};
# Only if `build buildLayeredImage`.
maxLayers = 3;
});
};
nixDaemonContainer = {
imageFile = nixDaemonImage;
image = "local/nix-daemon:latest";
volumes = [
"nix-daemon-store:/nix/store"
"nix-daemon-db:/nix/var/nix/db"
"nix-daemon-socket:/nix/var/nix/daemon-socket"
];
cmd = [
"nix"
"daemon"
];
};
podmanDaemonContainer = {
imageFile = podmanDaemonImage;
image = "local/podman-daemon:latest";
volumes = [
"podman-daemon-socket:/run/podman"
"podman-cache:/var/lib/container"
# Shared images, currently not needed.
"podman-shared:/var/lib/shared:ro"
];
privileged = true;
cmd = [
"podman"
"system"
"service"
"--time=0"
"unix:///run/podman/podman.sock"
"--log-level"
"info"
];
};
# Environment variables for all job containers.
envs = rec {
common = {
# Access to the nix daemon.
NIX_REMOTE = "daemon";
# Access to podman.
CONTAINER_HOST = "unix:///run/podman/podman.sock";
USER = "root";
PATH = "/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin:/usr/bin:/usr/sbin";
SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
NIX_SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
# For shells, source this file.
ENV = "${pkgs.nix}/etc/profile.d/nix-daemon.sh";
BASH_ENV = "${pkgs.nix}/etc/profile.d/nix-daemon.sh";
# Make a fake nixpkgs which throws when using
# `nix repl -f <nixpkgs>` for example.
NIX_PATH = "nixpkgs=${files.fakeNixpkgs}";
};
nix = common // {
IMAGE_OS_DIST = "nix";
};
alpine = common // {
IMAGE_OS_DIST = "alpine";
};
ubuntu = common // {
IMAGE_OS_DIST = "ubuntu";
};
};
registrationFlags = [
"--docker-volumes"
"gitlab-runner-scratch:/scratch"
"--docker-volumes"
"podman-daemon-socket:/run/podman"
"--docker-volumes-from"
"nix-daemon-container:ro"
"--docker-pull-policy"
"if-not-present"
"--docker-allowed-pull-policies"
"if-not-present"
"--docker-host"
"unix:///var/run/podman/podman.sock"
"--docker-network-mode"
"host"
];
in
{
imports = [ ./virtualization.nix ];
virtualisation.oci-containers = {
backend = "podman";
containers = {
nix-daemon-container = nixDaemonContainer;
podman-daemon-container = podmanDaemonContainer;
}
//
# Workaround to add the job images to the registry.
(lib.concatMapAttrs (name: image: {
"${name}-container" = {
imageFile = jobImages.${name};
image = "${imageNames.${name}}:latest";
extraOptions = [
"--volumes-from"
"nix-daemon-container:ro"
];
dependsOn = [ "nix-daemon-container" ];
cmd = [ "true" ];
};
}) jobImages);
};
# Define the Gitlab Runner.
services.gitlab-runner.services.podman-runner = {
description = runnerConfig.desc;
inherit registrationFlags;
authenticationTokenConfigFile = runnerConfig.tokenFile;
executor = "docker";
dockerImage = imageNames.default;
dockerAllowedImages = [ ];
dockerPrivileged = false;
requestConcurrency = 4;
preBuildScript = "${preBuildScript}/bin/gitlab-runner-pre-build-script";
};
}
@@ -1,21 +0,0 @@
root:x:0:
wheel:x:1:
kmem:x:2:
tty:x:3:
messagebus:x:4:
disk:x:6:
audio:x:17:
floppy:x:18:
uucp:x:19:
lp:x:20:
cdrom:x:24:
tape:x:25:
video:x:26:
dialout:x:27:
utmp:x:29:
adm:x:55:
keys:x:96:
users:x:100:
input:x:174:
nixbld:x:30000:nixbld1,nixbld10,nixbld11,nixbld12,nixbld13,nixbld14,nixbld15,nixbld16,nixbld17,nixbld18,nixbld19,nixbld2,nixbld20,nixbld21,nixbld22,nixbld23,nixbld24,nixbld25,nixbld26,nixbld27,nixbld28,nixbld29,nixbld3,nixbld30,nixbld31,nixbld32,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9
nogroup:x:65534:
@@ -1,11 +0,0 @@
passwd: files mymachines systemd
group: files mymachines systemd
shadow: files
hosts: files mymachines dns myhostname
networks: files
ethers: files
services: files
protocols: files
rpc: files
@@ -1,34 +0,0 @@
root:x:0:0:System administrator:/root:/bin/bash
nixbld1:x:30001:30000:Nix build user 1:/var/empty:/run/current-system/sw/bin/nologin
nixbld2:x:30002:30000:Nix build user 2:/var/empty:/run/current-system/sw/bin/nologin
nixbld3:x:30003:30000:Nix build user 3:/var/empty:/run/current-system/sw/bin/nologin
nixbld4:x:30004:30000:Nix build user 4:/var/empty:/run/current-system/sw/bin/nologin
nixbld5:x:30005:30000:Nix build user 5:/var/empty:/run/current-system/sw/bin/nologin
nixbld6:x:30006:30000:Nix build user 6:/var/empty:/run/current-system/sw/bin/nologin
nixbld7:x:30007:30000:Nix build user 7:/var/empty:/run/current-system/sw/bin/nologin
nixbld8:x:30008:30000:Nix build user 8:/var/empty:/run/current-system/sw/bin/nologin
nixbld9:x:30009:30000:Nix build user 9:/var/empty:/run/current-system/sw/bin/nologin
nixbld10:x:30010:30000:Nix build user 10:/var/empty:/run/current-system/sw/bin/nologin
nixbld11:x:30011:30000:Nix build user 11:/var/empty:/run/current-system/sw/bin/nologin
nixbld12:x:30012:30000:Nix build user 12:/var/empty:/run/current-system/sw/bin/nologin
nixbld13:x:30013:30000:Nix build user 13:/var/empty:/run/current-system/sw/bin/nologin
nixbld14:x:30014:30000:Nix build user 14:/var/empty:/run/current-system/sw/bin/nologin
nixbld15:x:30015:30000:Nix build user 15:/var/empty:/run/current-system/sw/bin/nologin
nixbld16:x:30016:30000:Nix build user 16:/var/empty:/run/current-system/sw/bin/nologin
nixbld17:x:30017:30000:Nix build user 17:/var/empty:/run/current-system/sw/bin/nologin
nixbld18:x:30018:30000:Nix build user 18:/var/empty:/run/current-system/sw/bin/nologin
nixbld19:x:30019:30000:Nix build user 19:/var/empty:/run/current-system/sw/bin/nologin
nixbld20:x:30020:30000:Nix build user 20:/var/empty:/run/current-system/sw/bin/nologin
nixbld21:x:30021:30000:Nix build user 21:/var/empty:/run/current-system/sw/bin/nologin
nixbld22:x:30022:30000:Nix build user 22:/var/empty:/run/current-system/sw/bin/nologin
nixbld23:x:30023:30000:Nix build user 23:/var/empty:/run/current-system/sw/bin/nologin
nixbld24:x:30024:30000:Nix build user 24:/var/empty:/run/current-system/sw/bin/nologin
nixbld25:x:30025:30000:Nix build user 25:/var/empty:/run/current-system/sw/bin/nologin
nixbld26:x:30026:30000:Nix build user 26:/var/empty:/run/current-system/sw/bin/nologin
nixbld27:x:30027:30000:Nix build user 27:/var/empty:/run/current-system/sw/bin/nologin
nixbld28:x:30028:30000:Nix build user 28:/var/empty:/run/current-system/sw/bin/nologin
nixbld29:x:30029:30000:Nix build user 29:/var/empty:/run/current-system/sw/bin/nologin
nixbld30:x:30030:30000:Nix build user 30:/var/empty:/run/current-system/sw/bin/nologin
nixbld31:x:30031:30000:Nix build user 31:/var/empty:/run/current-system/sw/bin/nologin
nixbld32:x:30032:30000:Nix build user 32:/var/empty:/run/current-system/sw/bin/nologin
nobody:x:65534:65534:Unprivileged account (don't use!):/var/empty:/run/current-system/sw/bin/nologin
@@ -1,2 +0,0 @@
[engine]
cgroup_manager = "cgroupfs"
@@ -1,2 +0,0 @@
/run/secrets/etc-pki-entitlement:/run/secrets/etc-pki-entitlement
/run/secrets/rhsm:/run/secrets/rhsm
@@ -1,12 +0,0 @@
{
"default": [
{
"type": "insecureAcceptAnything"
}
],
"transports": {
"docker-daemon": {
"": [{ "type": "insecureAcceptAnything" }]
}
}
}
@@ -1,2 +0,0 @@
unqualified-search-registries = ["registry.fedoraproject.org", "registry.access.redhat.com", "docker.io"]
short-name-mode = "enforcing"
@@ -1,5 +0,0 @@
[aliases]
"buildah" = "quay.io/buildah/stable"
"podman" = "quay.io/podman/stable"
"alpine" = "docker.io/library/alpine"
"ubuntu" = "docker.io/library/ubuntu"
@@ -1,27 +0,0 @@
# This is a default registries.d configuration file. You may
# add to this file or create additional files in registries.d/.
#
# lookaside: for reading/writing simple signing signatures
# lookaside-staging: for writing simple signing signatures, preferred over lookaside
#
# lookaside and lookaside-staging take a value of the following:
# lookaside: {schema}://location
#
# For reading signatures, schema may be http, https, or file.
# For writing signatures, schema may only be file.
# The default locations are built-in, for both reading and writing:
# /var/lib/containers/sigstore for root, or
# ~/.local/share/containers/sigstore for non-root users.
default-docker:
# lookaside: https://…
# lookaside-staging: file:///…
# The 'docker' indicator here is the start of the configuration
# for docker registries.
#
# docker:
#
# privateregistry.com:
# lookaside: https://privateregistry.com/sigstore/
# lookaside-staging: /mnt/nfs/privateregistry/sigstore
@@ -1,3 +0,0 @@
docker:
registry.access.redhat.com:
lookaside: https://access.redhat.com/webassets/docker/content/sigstore
@@ -1,3 +0,0 @@
docker:
registry.redhat.io:
lookaside: https://registry.redhat.io/containers/sigstore
@@ -1,15 +0,0 @@
[storage]
driver = "overlay"
runroot = "/run/containers/storage"
graphroot = "/var/lib/containers/storage"
[storage.options]
additionalimagestores = [
"/var/lib/shared",
"/usr/lib/containers/storage",
]
pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree_repos=""}
[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
mountopt = "nodev,fsync=0"
@@ -1,46 +0,0 @@
# Specific files for the job images.
#
# - `basicRoot`: Some basic root files for the `jobImages.nix`.
# - `fakeNixpkgs`: A fake Nixpkg directory which is set as `NIX_PATH=nixpkgs:<path>`
# which throws on load.
# - `nixConfig`: The Nix config with some options.
# - `containers`:
# These are some files which are copied to the job images needed for
# `buildah` (`podman`):
#
# ```bash
# podman create --name temp-buildah quay.io/buildah/stable:latest
# podman cp temp-buildah:/etc/containers ./etc/
# find ./etc -type d -empty -delete
# podman container rm temp-buildah
#```
#
{ pkgs, ... }:
let
# We need proper derivations to add it to the nixImageBase.
mkDrv =
name: src:
pkgs.stdenv.mkDerivation {
inherit name src;
installPhase = ''
mkdir -p $out
cp -r $src/* $out/
'';
};
in
{
basicRoot = mkDrv "basic-root-files" ./basicRoot;
containers = mkDrv "containers-files" ./containers;
fakeNixpkgs = mkDrv "fake-nixpkgs" ./fake-nixpkgs;
nixConfig = pkgs.writeTextFile {
name = "nix.conf";
destination = "/etc/nix/nix.conf";
text = ''
accept-flake-config = true
experimental-features = nix-command flakes
max-jobs = auto
'';
};
}
@@ -1,10 +0,0 @@
_:
throw ''
This container doesn't include nixpkgs.
The best way to work around that is to pin your dependencies. See
https://nix.dev/tutorials/first-steps/towards-reproducibility-pinning-nixpkgs.html
Or if you must, override the NIX_PATH environment variable with eg:
"NIX_PATH=nixpkgs=channel:nixos-unstable"
''
@@ -1,55 +0,0 @@
{ writeShellScriptBin, nix }:
writeShellScriptBin "gitlab-runner-pre-build-script"
# bash
''
set -e
set -u
function section_start() {
local name="$1"
shift
echo -e "\e[0Ksection_start:$(date +%s):$name[collapsed=true]\r\e[0K$*"
}
function section_end() {
local name="$1"
echo -e "\e[0Ksection_end:$(date +%s):$name\r\e[0K"
}
function setup() {
# We need to allow modification of nix config for cachix as
# otherwise it is link to the read only file in the store.
cp --remove-destination \
"$(readlink -f /etc/nix/nix.conf)" /etc/nix/nix.conf
# shellcheck disable=SC1091
. "${nix}/etc/profile.d/nix-daemon.sh"
}
function setup_pipeline_scratch_dir() {
scratch_dir="/scratch/$CI_PIPELINE_ID"
echo "Create scrtach directory for pipeline: $scratch_dir"
mkdir -p "$scratch_dir" || {
echo "Could not create scratch dir '$scratch_dir'." >&2
exit 1
}
export CI_CUSTOM_SCRATCH_DIR="$scratch_dir"
}
function print_info() {
echo "Nix version:"
nix --version
}
function main() {
print_info
setup
setup_pipeline_scratch_dir
}
section_start gitlab-runner-prebuild "Gitlab-Runner PreBuild Script"
main "$@"
section_end gitlab-runner-prebuild
''
@@ -1,43 +0,0 @@
{ lib, ... }:
{
virtualisation.docker = {
enable = lib.mkForce false;
};
virtualisation.podman = {
enable = true;
# Create a `docker` alias for podman, to use it as a drop-in replacement
# dockerCompat = true;
dockerSocket = {
enable = true;
};
# Required for containers under podman-compose to be able to talk to each other.
defaultNetwork.settings.dns_enabled = true;
autoPrune = {
dates = "weekly";
flags = [
"--filter"
"label!=no-prune"
"--volumes"
"--log-level"
"debug"
];
};
};
virtualisation.containers.storage.settings = {
storage = {
driver = "overlay";
graphroot = "/var/lib/containers/storage";
runroot = "/run/containers/storage";
# Does not work currently.
options.overlay = {
mountopt = "nodev,metacopy=on";
};
};
};
}
@@ -1,12 +0,0 @@
{
runnerConfig,
}:
# This is the runner config for the `nixosConfiguration.services.gitlab-runner.services.X`
{
services.gitlab-runner.services.shell-runner = {
description = runnerConfig.desc;
authenticationTokenConfigFile = runnerConfig.tokenFile;
executor = "shell";
};
}
-146
View File
@@ -1,146 +0,0 @@
import json
import os
from dataclasses import dataclass
from pathlib import Path
from string import Template
from typing import Any
@dataclass
class Runner:
name: str
tokenFile: str
id: str
token: str
@dataclass
class Machines:
gitlab: Any
gitlab_runner: Any
@dataclass
class Nix:
jq: str
gitlab_state_path: str
create_runner_payload_file: str
auth_payload_file: str
runner_token_env_file: str
# Some global variables to work in the tests.
out_dir = os.environ.get("out", os.getcwd())
nix = Nix(
jq=JQ_BINARY,
gitlab_state_path=GITLAB_STATE_PATH,
auth_payload_file=AUTH_PAYLOAD_FILE,
create_runner_payload_file=CREATE_RUNNER_PAYLOAD_FILE,
runner_token_env_file=RUNNER_TOKEN_ENV_FILE,
)
vms = Machines(gitlab, gitlab_runner)
runnerConfigs: dict[str, Runner] = {}
def wait_for_services():
vms.gitlab.wait_for_unit("gitaly.service")
vms.gitlab.wait_for_unit("gitlab-workhorse.service")
vms.gitlab.wait_for_unit("gitlab.service")
vms.gitlab.wait_for_unit("gitlab-sidekiq.service")
vms.gitlab.wait_for_file(f"{nix.gitlab_state_path}/tmp/sockets/gitlab.socket")
vms.gitlab.wait_until_succeeds("curl -sSf http://gitlab/users/sign_in")
def test_connection():
"""
Test the connection to Gitlab and check if it is reachable from the runner VM.
"""
print("==> Getting secrets and headers.")
vms.gitlab.succeed(
"cp /var/gitlab/state/config/secrets.yml /root/gitlab-secrets.yml"
)
vms.gitlab.succeed(
f"echo \"Authorization: Bearer $(curl -X POST -H 'Content-Type: application/json' -d @{nix.auth_payload_file} http://gitlab/oauth/token | {nix.jq} -r '.access_token')\" >/tmp/headers"
)
vms.gitlab.copy_from_vm("/tmp/headers")
out_dir = os.environ.get("out", os.getcwd())
vms.gitlab_runner.copy_from_host(str(Path(out_dir, "headers")), "/tmp/headers")
print("==> Testing connection.")
vms.gitlab_runner.succeed("curl -v -H @/tmp/headers http://gitlab/api/v4/version")
def test_register_runner(name: str, tokenFile: str):
"""
Register the runner in Gitlab and write the token file to be picked up by
the gitlab-runner service on the other VM.
"""
r = Runner(
name=name,
tokenFile=tokenFile,
token="",
id="",
)
runnerConfigs[r.name] = r
print(f"==> Create Runner '{r.name}'")
resp = vms.gitlab.execute(
f"""
curl -s -X POST \
-H 'Content-Type: application/json' \
-H @/tmp/headers \
-d @{nix.create_runner_payload_file} \
http://gitlab/api/v4/user/runners
"""
)[1]
obj = json.loads(resp)
r.id = obj["id"]
r.token = obj["token"]
print(f"==> Registered runner '{r.id}' with token '{r.token}'.")
# Push the token to the runner machine.
print("==> Push runner token to machine.")
tokenF = Path(out_dir, f"token-{r.name}.env")
with open(nix.runner_token_env_file, "r") as f:
tokenData = Template(f.read()).substitute({"token": r.token})
with open(tokenF, "w") as w:
w.write(tokenData)
vms.gitlab_runner.copy_from_host(str(tokenF), r.tokenFile)
def restart_gitlab_runner_service(runnerConfigs):
print("==> Restart Gitlab Runner")
if any([n == "podman" for n in runnerConfigs.keys()]):
vms.gitlab_runner.wait_for_unit("podman-nix-daemon-container.service")
vms.gitlab_runner.wait_for_unit("podman-podman-daemon-container.service")
vms.gitlab_runner.systemctl("restart gitlab-runner.service")
vms.gitlab_runner.wait_for_unit("gitlab-runner.service")
def test_runner_registered(r: Runner):
"""
Test that the runner `r` is registered in Gitlab and its status is active.
"""
print(f"==> Check that runner '{r.name}' is registered.")
resp = vms.gitlab.execute(
f"""
curl -s -X GET \
-H 'Content-Type: application/json' \
-H @/tmp/headers \
http://gitlab/api/v4/runners/{r.id}"""
)[1]
runnerStatus = json.loads(resp)
if not runnerStatus["active"]:
raise Exception(
f"Runner '{r.name}' [id: '{r.id}'] status is not active: {resp}"
)
-34
View File
@@ -1,34 +0,0 @@
# A test that imports k3s airgapped images and verifies that all expected images are present
import ../make-test-python.nix (
{ lib, k3s, ... }:
{
name = "${k3s.name}-airgap-images";
meta.maintainers = lib.teams.k3s.members;
nodes.machine = _: {
# k3s uses enough resources the default vm fails.
virtualisation.memorySize = 1536;
virtualisation.diskSize = 4096;
services.k3s = {
enable = true;
role = "server";
package = k3s;
# Slightly reduce resource usage
extraFlags = [
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
"--disable traefik"
];
images = [ k3s.airgap-images ];
};
};
testScript = ''
machine.wait_for_unit("k3s")
machine.wait_until_succeeds("journalctl -r --no-pager -u k3s | grep \"Imported images from /var/lib/rancher/k3s/agent/images/\"")
'';
}
)
-204
View File
@@ -1,204 +0,0 @@
# Tests whether container images are imported and auto deploying Helm charts,
# including the bundled traefik, work
import ../make-test-python.nix (
{
k3s,
lib,
pkgs,
...
}:
let
testImageEnv = pkgs.buildEnv {
name = "k3s-pause-image-env";
paths = with pkgs; [
busybox
hello
];
};
testImage = pkgs.dockerTools.buildImage {
name = "test.local/test";
tag = "local";
# Slightly reduces the time needed to import image
compressor = "zstd";
copyToRoot = testImageEnv;
};
# pack the test helm chart as a .tgz archive
package =
pkgs.runCommand "k3s-test-chart.tgz"
{
nativeBuildInputs = [ pkgs.kubernetes-helm ];
chart = builtins.toJSON {
name = "k3s-test-chart";
version = "0.1.0";
};
values = builtins.toJSON {
restartPolicy = "Never";
runCommand = "";
image = {
repository = "foo";
tag = "1.0.0";
};
};
job = builtins.toJSON {
apiVersion = "batch/v1";
kind = "Job";
metadata = {
name = "{{ .Release.Name }}";
namespace = "{{ .Release.Namespace }}";
};
spec = {
template = {
spec = {
containers = [
{
name = "test";
image = "{{ .Values.image.repository }}:{{ .Values.image.tag }}";
command = [ "sh" ];
args = [
"-c"
"{{ .Values.runCommand }}"
];
}
];
restartPolicy = "{{ .Values.restartPolicy }}";
};
};
};
};
passAsFile = [
"values"
"chart"
"job"
];
}
''
mkdir -p chart/templates
cp "$chartPath" chart/Chart.yaml
cp "$valuesPath" chart/values.yaml
cp "$jobPath" chart/templates/job.json
helm package chart
mv ./*.tgz $out
'';
# The common Helm chart that is used in this test
testChart = {
inherit package;
values = {
runCommand = "hello";
image = {
repository = testImage.imageName;
tag = testImage.imageTag;
};
};
};
in
{
name = "${k3s.name}-auto-deploy-helm";
meta.maintainers = lib.teams.k3s.members;
nodes.machine =
{ pkgs, ... }:
{
# k3s uses enough resources the default vm fails.
virtualisation = {
memorySize = 1536;
diskSize = 4096;
};
environment.systemPackages = [ pkgs.yq-go ];
services.k3s = {
enable = true;
package = k3s;
# Slightly reduce resource usage
extraFlags = [
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
];
images = [
# Provides the k3s Helm controller
k3s.airgap-images
testImage
];
autoDeployCharts = {
# regular test chart that should get installed
hello = testChart;
# disabled chart that should not get installed
disabled = testChart // {
enable = false;
};
# chart with values set via YAML file
values-file = testChart // {
# Remove unsafeDiscardStringContext workaround when Nix can convert a string to a path
# https://github.com/NixOS/nix/issues/12407
values =
/.
+ builtins.unsafeDiscardStringContext (
builtins.toFile "k3s-test-chart-values.yaml" ''
runCommand: "echo 'Hello, file!'"
image:
repository: test.local/test
tag: local
''
);
};
# advanced chart that should get installed in the "test" namespace with a custom
# timeout and overridden values
advanced = testChart // {
# create the "test" namespace via extraDeploy for testing
extraDeploy = [
{
apiVersion = "v1";
kind = "Namespace";
metadata.name = "test";
}
];
extraFieldDefinitions = {
spec = {
# overwrite chart values
valuesContent = ''
runCommand: "echo 'advanced hello'"
image:
repository: ${testImage.imageName}
tag: ${testImage.imageTag}
'';
# overwrite the chart namespace
targetNamespace = "test";
# set a custom timeout
timeout = "69s";
};
};
};
};
};
};
testScript = # python
''
import json
machine.wait_for_unit("k3s")
# check existence/absence of chart manifest files
machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/hello.yaml")
machine.succeed("test ! -e /var/lib/rancher/k3s/server/manifests/disabled.yaml")
machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/values-file.yaml")
machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/advanced.yaml")
# check that the timeout is set correctly, select only the first doc in advanced.yaml
advancedManifest = json.loads(machine.succeed("yq -o json '.items[0]' /var/lib/rancher/k3s/server/manifests/advanced.yaml"))
t.assertEqual(advancedManifest["spec"]["timeout"], "69s", "unexpected value for spec.timeout")
# wait for test jobs to complete
machine.wait_until_succeeds("kubectl wait --for=condition=complete job/hello", timeout=180)
machine.wait_until_succeeds("kubectl wait --for=condition=complete job/values-file", timeout=180)
machine.wait_until_succeeds("kubectl -n test wait --for=condition=complete job/advanced", timeout=180)
# check output of test jobs
hello_output = machine.succeed("kubectl logs -l batch.kubernetes.io/job-name=hello")
values_file_output = machine.succeed("kubectl logs -l batch.kubernetes.io/job-name=values-file")
advanced_output = machine.succeed("kubectl -n test logs -l batch.kubernetes.io/job-name=advanced")
# strip the output to remove trailing whitespaces
t.assertEqual(hello_output.rstrip(), "Hello, world!", "unexpected output of hello job")
t.assertEqual(values_file_output.rstrip(), "Hello, file!", "unexpected output of values file job")
t.assertEqual(advanced_output.rstrip(), "advanced hello", "unexpected output of advanced job")
# wait for bundled traefik deployment
machine.wait_until_succeeds("kubectl -n kube-system rollout status deployment traefik", timeout=180)
'';
}
)
-124
View File
@@ -1,124 +0,0 @@
# Tests whether container images are imported and auto deploying manifests work
import ../make-test-python.nix (
{
pkgs,
lib,
k3s,
...
}:
let
pauseImageEnv = pkgs.buildEnv {
name = "k3s-pause-image-env";
paths = with pkgs; [
tini
(lib.hiPrio coreutils)
busybox
];
};
pauseImage = pkgs.dockerTools.buildImage {
name = "test.local/pause";
tag = "local";
copyToRoot = pauseImageEnv;
config.Entrypoint = [
"/bin/tini"
"--"
"/bin/sleep"
"inf"
];
};
helloImage = pkgs.dockerTools.buildImage {
name = "test.local/hello";
tag = "local";
copyToRoot = pkgs.hello;
config.Entrypoint = [ "${pkgs.hello}/bin/hello" ];
};
in
{
name = "${k3s.name}-auto-deploy";
nodes.machine =
{ pkgs, ... }:
{
environment.systemPackages = [ k3s ];
# k3s uses enough resources the default vm fails.
virtualisation.memorySize = 1536;
virtualisation.diskSize = 4096;
services.k3s.enable = true;
services.k3s.role = "server";
services.k3s.package = k3s;
# Slightly reduce resource usage
services.k3s.extraFlags = [
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
"--disable traefik"
"--pause-image test.local/pause:local"
];
services.k3s.images = [
pauseImage
helloImage
];
services.k3s.manifests = {
absent = {
enable = false;
content = {
apiVersion = "v1";
kind = "Namespace";
metadata.name = "absent";
};
};
present = {
target = "foo-namespace.yaml";
content = {
apiVersion = "v1";
kind = "Namespace";
metadata.name = "foo";
};
};
hello.content = {
apiVersion = "batch/v1";
kind = "Job";
metadata.name = "hello";
spec = {
template.spec = {
containers = [
{
name = "hello";
image = "test.local/hello:local";
}
];
restartPolicy = "OnFailure";
};
};
};
};
};
testScript = # python
''
start_all()
machine.wait_for_unit("k3s")
# check existence of the manifest files
machine.fail("ls /var/lib/rancher/k3s/server/manifests/absent.yaml")
machine.succeed("ls /var/lib/rancher/k3s/server/manifests/foo-namespace.yaml")
machine.succeed("ls /var/lib/rancher/k3s/server/manifests/hello.yaml")
# check if container images got imported
machine.wait_until_succeeds("crictl img | grep 'test\.local/pause'")
machine.wait_until_succeeds("crictl img | grep 'test\.local/hello'")
# check if resources of manifests got created
machine.wait_until_succeeds("kubectl get ns foo")
machine.wait_until_succeeds("kubectl wait --for=condition=complete job/hello")
machine.fail("kubectl get ns absent")
'';
meta.maintainers = lib.teams.k3s.members;
}
)
-59
View File
@@ -1,59 +0,0 @@
# A test that containerdConfigTemplate settings get written to containerd/config.toml
import ../make-test-python.nix (
{
pkgs,
lib,
k3s,
...
}:
let
nodeName = "test";
in
{
name = "${k3s.name}-containerd-config";
nodes.machine =
{ ... }:
{
environment.systemPackages = [ pkgs.jq ];
# k3s uses enough resources the default vm fails.
virtualisation.memorySize = 1536;
virtualisation.diskSize = 4096;
services.k3s = {
enable = true;
package = k3s;
# Slightly reduce resource usage
extraFlags = [
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
"--disable traefik"
"--node-name ${nodeName}"
];
containerdConfigTemplate = ''
# Base K3s config
{{ template "base" . }}
# MAGIC COMMENT
'';
};
};
testScript = # python
''
start_all()
machine.wait_for_unit("k3s")
# wait until the node is ready
machine.wait_until_succeeds(r"""kubectl get node ${nodeName} -ojson | jq -e '.status.conditions[] | select(.type == "Ready") | .status == "True"'""")
# test whether the config template file contains the magic comment
out=machine.succeed("cat /var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl")
t.assertIn("MAGIC COMMENT", out, "the containerd config template does not contain the magic comment")
# test whether the config file contains the magic comment
out=machine.succeed("cat /var/lib/rancher/k3s/agent/etc/containerd/config.toml")
t.assertIn("MAGIC COMMENT", out, "the containerd config does not contain the magic comment")
'';
meta.maintainers = lib.teams.k3s.members;
}
)
-34
View File
@@ -1,34 +0,0 @@
{
system ? builtins.currentSystem,
pkgs ? import ../../.. { inherit system; },
lib ? pkgs.lib,
}:
let
allK3s = lib.filterAttrs (
n: _: lib.strings.hasPrefix "k3s_" n && (builtins.tryEval pkgs.${n}).success
) pkgs;
in
{
airgap-images = lib.mapAttrs (
_: k3s: import ./airgap-images.nix { inherit system pkgs k3s; }
) allK3s;
auto-deploy = lib.mapAttrs (_: k3s: import ./auto-deploy.nix { inherit system pkgs k3s; }) allK3s;
auto-deploy-charts = lib.mapAttrs (
_: k3s: import ./auto-deploy-charts.nix { inherit system pkgs k3s; }
) allK3s;
containerd-config = lib.mapAttrs (
_: k3s: import ./containerd-config.nix { inherit system pkgs k3s; }
) allK3s;
etcd = lib.mapAttrs (
_: k3s:
import ./etcd.nix {
inherit system pkgs k3s;
inherit (pkgs) etcd;
}
) allK3s;
kubelet-config = lib.mapAttrs (
_: k3s: import ./kubelet-config.nix { inherit system pkgs k3s; }
) allK3s;
multi-node = lib.mapAttrs (_: k3s: import ./multi-node.nix { inherit system pkgs k3s; }) allK3s;
single-node = lib.mapAttrs (_: k3s: import ./single-node.nix { inherit system pkgs k3s; }) allK3s;
}
-126
View File
@@ -1,126 +0,0 @@
# Tests K3s with Etcd backend
import ../make-test-python.nix (
{
pkgs,
lib,
k3s,
etcd,
...
}:
{
name = "${k3s.name}-etcd";
nodes = {
etcd =
{ ... }:
{
services.etcd = {
enable = true;
openFirewall = true;
listenClientUrls = [
"http://192.168.1.1:2379"
"http://127.0.0.1:2379"
];
listenPeerUrls = [ "http://192.168.1.1:2380" ];
initialAdvertisePeerUrls = [ "http://192.168.1.1:2380" ];
initialCluster = [ "etcd=http://192.168.1.1:2380" ];
};
networking = {
useDHCP = false;
defaultGateway = "192.168.1.1";
interfaces.eth1.ipv4.addresses = pkgs.lib.mkForce [
{
address = "192.168.1.1";
prefixLength = 24;
}
];
};
};
k3s =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [ jq ];
# k3s uses enough resources the default vm fails.
virtualisation.memorySize = 1536;
virtualisation.diskSize = 4096;
services.k3s = {
enable = true;
role = "server";
package = k3s;
extraFlags = [
"--datastore-endpoint=\"http://192.168.1.1:2379\""
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
"--disable traefik"
"--node-ip 192.168.1.2"
];
};
networking = {
firewall = {
allowedTCPPorts = [
2379
2380
6443
];
allowedUDPPorts = [ 8472 ];
};
useDHCP = false;
defaultGateway = "192.168.1.2";
interfaces.eth1.ipv4.addresses = pkgs.lib.mkForce [
{
address = "192.168.1.2";
prefixLength = 24;
}
];
};
};
};
testScript = # python
''
with subtest("should start etcd"):
etcd.start()
etcd.wait_for_unit("etcd.service")
with subtest("should wait for etcdctl endpoint status to succeed"):
etcd.wait_until_succeeds("etcdctl endpoint status")
with subtest("should wait for etcdctl endpoint health to succeed"):
etcd.wait_until_succeeds("etcdctl endpoint health")
with subtest("should start k3s"):
k3s.start()
k3s.wait_for_unit("k3s")
with subtest("should test if kubectl works"):
k3s.wait_until_succeeds("k3s kubectl get node")
with subtest("should wait for service account to show up; takes a sec"):
k3s.wait_until_succeeds("k3s kubectl get serviceaccount default")
with subtest("should create a sample secret object"):
k3s.succeed("k3s kubectl create secret generic nixossecret --from-literal thesecret=abacadabra")
with subtest("should check if secret is correct"):
k3s.wait_until_succeeds("[[ $(kubectl get secrets nixossecret -o json | jq -r .data.thesecret | base64 -d) == abacadabra ]]")
with subtest("should have a secret in database"):
etcd.wait_until_succeeds("[[ $(etcdctl get /registry/secrets/default/nixossecret | head -c1 | wc -c) -ne 0 ]]")
with subtest("should delete the secret"):
k3s.succeed("k3s kubectl delete secret nixossecret")
with subtest("should not have a secret in database"):
etcd.wait_until_fails("[[ $(etcdctl get /registry/secrets/default/nixossecret | head -c1 | wc -c) -ne 0 ]]")
'';
meta.maintainers = etcd.meta.maintainers ++ lib.teams.k3s.members;
}
)
-76
View File
@@ -1,76 +0,0 @@
# A test that sets extra kubelet configuration and enables graceful node shutdown
import ../make-test-python.nix (
{
pkgs,
lib,
k3s,
...
}:
let
nodeName = "test";
shutdownGracePeriod = "1m13s";
shutdownGracePeriodCriticalPods = "13s";
podsPerCore = 3;
memoryThrottlingFactor = 0.69;
containerLogMaxSize = "5Mi";
in
{
name = "${k3s.name}-kubelet-config";
nodes.machine =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.jq ];
# k3s uses enough resources the default vm fails.
virtualisation.memorySize = 1536;
virtualisation.diskSize = 4096;
services.k3s = {
enable = true;
package = k3s;
# Slightly reduce resource usage
extraFlags = [
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
"--disable traefik"
"--node-name ${nodeName}"
];
gracefulNodeShutdown = {
enable = true;
inherit shutdownGracePeriod shutdownGracePeriodCriticalPods;
};
extraKubeletConfig = {
inherit podsPerCore memoryThrottlingFactor containerLogMaxSize;
};
};
};
testScript = # python
''
import json
start_all()
machine.wait_for_unit("k3s")
# wait until the node is ready
machine.wait_until_succeeds(r"""kubectl get node ${nodeName} -ojson | jq -e '.status.conditions[] | select(.type == "Ready") | .status == "True"'""")
# test whether the kubelet registered an inhibitor lock
machine.succeed("systemd-inhibit --list --no-legend | grep \"kubelet.*k3s-server.*shutdown\"")
# run kubectl proxy in the background, close stdout through redirection to not wait for the command to finish
machine.execute("kubectl proxy --address 127.0.0.1 --port=8001 >&2 &")
machine.wait_until_succeeds("nc -z 127.0.0.1 8001")
# get the kubeletconfig
kubelet_config=json.loads(machine.succeed("curl http://127.0.0.1:8001/api/v1/nodes/${nodeName}/proxy/configz | jq '.kubeletconfig'"))
with subtest("Kubelet config values are set correctly"):
t.assertEqual(kubelet_config["shutdownGracePeriod"], "${shutdownGracePeriod}")
t.assertEqual(kubelet_config["shutdownGracePeriodCriticalPods"], "${shutdownGracePeriodCriticalPods}")
t.assertEqual(kubelet_config["podsPerCore"], ${toString podsPerCore})
t.assertEqual(kubelet_config["memoryThrottlingFactor"], ${toString memoryThrottlingFactor})
t.assertEqual(kubelet_config["containerLogMaxSize"],"${containerLogMaxSize}")
'';
meta.maintainers = lib.teams.k3s.members;
}
)
-200
View File
@@ -1,200 +0,0 @@
# A test that runs a multi-node k3s cluster and verify pod networking works across nodes
import ../make-test-python.nix (
{
pkgs,
lib,
k3s,
...
}:
let
imageEnv = pkgs.buildEnv {
name = "k3s-pause-image-env";
paths = with pkgs; [
tini
bashInteractive
coreutils
socat
];
};
pauseImage = pkgs.dockerTools.buildImage {
name = "test.local/pause";
tag = "local";
copyToRoot = imageEnv;
config.Entrypoint = [
"/bin/tini"
"--"
"/bin/sleep"
"inf"
];
};
# A daemonset that responds 'server' on port 8000
networkTestDaemonset = pkgs.writeText "test.yml" ''
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: test
labels:
name: test
spec:
selector:
matchLabels:
name: test
template:
metadata:
labels:
name: test
spec:
containers:
- name: test
image: test.local/pause:local
imagePullPolicy: Never
resources:
limits:
memory: 20Mi
command: ["socat", "TCP4-LISTEN:8000,fork", "EXEC:echo server"]
'';
tokenFile = pkgs.writeText "token" "p@s$w0rd";
in
{
name = "${k3s.name}-multi-node";
nodes = {
server =
{ nodes, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
gzip
jq
];
# k3s uses enough resources the default vm fails.
virtualisation.memorySize = 1536;
virtualisation.diskSize = 4096;
services.k3s = {
inherit tokenFile;
enable = true;
role = "server";
package = k3s;
images = [ pauseImage ];
clusterInit = true;
extraFlags = [
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
"--disable traefik"
"--pause-image test.local/pause:local"
"--node-ip ${nodes.server.networking.primaryIPAddress}"
# The interface selection logic of flannel would normally use eth0, as the nixos
# testing driver sets a default route via dev eth0. However, in test setups we
# have to use eth1 for inter-node communication.
"--flannel-iface eth1"
];
};
networking.firewall.allowedTCPPorts = [
2379
2380
6443
];
networking.firewall.allowedUDPPorts = [ 8472 ];
};
server2 =
{ nodes, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
gzip
jq
];
virtualisation.memorySize = 1536;
virtualisation.diskSize = 4096;
services.k3s = {
inherit tokenFile;
enable = true;
package = k3s;
images = [ pauseImage ];
serverAddr = "https://${nodes.server.networking.primaryIPAddress}:6443";
clusterInit = false;
extraFlags = [
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
"--disable traefik"
"--pause-image test.local/pause:local"
"--node-ip ${nodes.server2.networking.primaryIPAddress}"
"--flannel-iface eth1"
];
};
networking.firewall.allowedTCPPorts = [
2379
2380
6443
];
networking.firewall.allowedUDPPorts = [ 8472 ];
};
agent =
{ nodes, pkgs, ... }:
{
virtualisation.memorySize = 1024;
virtualisation.diskSize = 2048;
services.k3s = {
inherit tokenFile;
enable = true;
role = "agent";
package = k3s;
images = [ pauseImage ];
serverAddr = "https://${nodes.server2.networking.primaryIPAddress}:6443";
extraFlags = [
"--pause-image test.local/pause:local"
"--node-ip ${nodes.agent.networking.primaryIPAddress}"
"--flannel-iface eth1"
];
};
networking.firewall.allowedTCPPorts = [ 6443 ];
networking.firewall.allowedUDPPorts = [ 8472 ];
};
};
testScript = # python
''
start_all()
machines = [server, server2, agent]
for m in machines:
m.wait_for_unit("k3s")
# wait for the agent to show up
server.wait_until_succeeds("k3s kubectl get node agent")
for m in machines:
m.succeed("k3s check-config")
server.succeed("k3s kubectl cluster-info")
# Also wait for our service account to show up; it takes a sec
server.wait_until_succeeds("k3s kubectl get serviceaccount default")
# Now create a pod on each node via a daemonset and verify they can talk to each other.
server.succeed("k3s kubectl apply -f ${networkTestDaemonset}")
server.wait_until_succeeds(f'[ "$(k3s kubectl get ds test -o json | jq .status.numberReady)" -eq {len(machines)} ]')
# Get pod IPs
pods = server.succeed("k3s kubectl get po -o json | jq '.items[].metadata.name' -r").splitlines()
pod_ips = [server.succeed(f"k3s kubectl get po {name} -o json | jq '.status.podIP' -cr").strip() for name in pods]
# Verify each server can ping each pod ip
for pod_ip in pod_ips:
server.succeed(f"ping -c 1 {pod_ip}")
server2.succeed(f"ping -c 1 {pod_ip}")
agent.succeed(f"ping -c 1 {pod_ip}")
# Verify the pods can talk to each other
for pod in pods:
resp = server.succeed(f"k3s kubectl exec {pod} -- socat TCP:{pod_ip}:8000 -")
t.assertEqual(resp.strip(), "server")
'';
meta.maintainers = lib.teams.k3s.members;
}
)
-115
View File
@@ -1,115 +0,0 @@
# A test that runs a single node k3s cluster and verify a pod can run
import ../make-test-python.nix (
{
pkgs,
lib,
k3s,
...
}:
let
imageEnv = pkgs.buildEnv {
name = "k3s-pause-image-env";
paths = with pkgs; [
tini
(lib.hiPrio coreutils)
busybox
];
};
pauseImage = pkgs.dockerTools.streamLayeredImage {
name = "test.local/pause";
tag = "local";
contents = imageEnv;
config.Entrypoint = [
"/bin/tini"
"--"
"/bin/sleep"
"inf"
];
};
testPodYaml = pkgs.writeText "test.yml" ''
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- name: test
image: test.local/pause:local
imagePullPolicy: Never
command: ["sh", "-c", "sleep inf"]
'';
in
{
name = "${k3s.name}-single-node";
nodes.machine =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
k3s
gzip
];
# k3s uses enough resources the default vm fails.
virtualisation.memorySize = 1536;
virtualisation.diskSize = 4096;
services.k3s.enable = true;
services.k3s.role = "server";
services.k3s.package = k3s;
# Slightly reduce resource usage
services.k3s.extraFlags = [
"--disable coredns"
"--disable local-storage"
"--disable metrics-server"
"--disable servicelb"
"--disable traefik"
"--pause-image test.local/pause:local"
];
users.users = {
noprivs = {
isNormalUser = true;
description = "Can't access k3s by default";
password = "*";
};
};
};
testScript = # python
''
start_all()
machine.wait_for_unit("k3s")
machine.succeed("kubectl cluster-info")
machine.fail("sudo -u noprivs kubectl cluster-info")
machine.succeed("k3s check-config")
machine.succeed(
"${pauseImage} | ctr image import -"
)
# Also wait for our service account to show up; it takes a sec
machine.wait_until_succeeds("kubectl get serviceaccount default")
machine.succeed("kubectl apply -f ${testPodYaml}")
machine.succeed("kubectl wait --for 'condition=Ready' pod/test")
machine.succeed("kubectl delete -f ${testPodYaml}")
# regression test for #176445
machine.fail("journalctl -o cat -u k3s.service | grep 'ipset utility not found'")
with subtest("Run k3s-killall"):
# Call the killall script with a clean path to assert that
# all required commands are wrapped
output = machine.succeed("PATH= ${k3s}/bin/k3s-killall.sh 2>&1 | tee /dev/stderr")
t.assertNotIn("command not found", output, "killall script contains unknown command")
# Check that killall cleaned up properly
machine.fail("systemctl is-active k3s.service")
machine.fail("systemctl list-units | grep containerd")
machine.fail("ip link show | awk -F': ' '{print $2}' | grep -e flannel -e cni0")
machine.fail("ip netns show | grep cni-")
'';
meta.maintainers = lib.teams.k3s.members;
}
)
+40
View File
@@ -0,0 +1,40 @@
# A test that imports k3s airgapped images and verifies that all expected images are present
{
pkgs,
lib,
rancherDistro,
rancherPackage,
serviceName,
disabledComponents,
coreImages,
vmResources,
...
}:
{
name = "${rancherPackage.name}-airgap-images";
nodes.machine = _: {
virtualisation = vmResources;
services.${rancherDistro} = {
enable = true;
role = "server";
package = rancherPackage;
disable = disabledComponents;
images =
coreImages
++ {
k3s = [ rancherPackage.airgap-images ];
rke2 = [ ]; # RKE2 already includes its airgap-images in coreImages
}
.${rancherDistro};
};
};
testScript = ''
machine.wait_for_unit("${serviceName}")
machine.wait_until_succeeds("journalctl -r --no-pager -u ${serviceName} | grep \"Imported images from /var/lib/rancher/${rancherDistro}/agent/images/\"")
'';
meta.maintainers = lib.teams.k3s.members ++ pkgs.rke2.meta.maintainers;
}
+230
View File
@@ -0,0 +1,230 @@
# Tests whether container images are imported and auto deploying Helm charts,
# including the bundled traefik or ingress-nginx, work
{
pkgs,
lib,
rancherDistro,
rancherPackage,
serviceName,
disabledComponents,
coreImages,
vmResources,
...
}:
let
testImageEnv = pkgs.buildEnv {
name = "${rancherDistro}-pause-image-env";
paths = with pkgs; [
busybox
hello
];
};
testImage = pkgs.dockerTools.buildImage {
name = "test.local/test";
tag = "local";
# Slightly reduces the time needed to import image
compressor = "zstd";
copyToRoot = testImageEnv;
};
# pack the test helm chart as a .tgz archive
package =
pkgs.runCommand "${rancherDistro}-test-chart.tgz"
{
nativeBuildInputs = [ pkgs.kubernetes-helm ];
chart = builtins.toJSON {
name = "${rancherDistro}-test-chart";
version = "0.1.0";
};
values = builtins.toJSON {
restartPolicy = "Never";
runCommand = "";
image = {
repository = "foo";
tag = "1.0.0";
};
};
job = builtins.toJSON {
apiVersion = "batch/v1";
kind = "Job";
metadata = {
name = "{{ .Release.Name }}";
namespace = "{{ .Release.Namespace }}";
};
spec = {
template = {
spec = {
containers = [
{
name = "test";
image = "{{ .Values.image.repository }}:{{ .Values.image.tag }}";
command = [ "sh" ];
args = [
"-c"
"{{ .Values.runCommand }}"
];
}
];
restartPolicy = "{{ .Values.restartPolicy }}";
};
};
};
};
passAsFile = [
"values"
"chart"
"job"
];
}
''
mkdir -p chart/templates
cp "$chartPath" chart/Chart.yaml
cp "$valuesPath" chart/values.yaml
cp "$jobPath" chart/templates/job.json
helm package chart
mv ./*.tgz $out
'';
# The common Helm chart that is used in this test
testChart = {
inherit package;
values = {
runCommand = "hello";
image = {
repository = testImage.imageName;
tag = testImage.imageTag;
};
};
};
in
{
name = "${rancherPackage.name}-auto-deploy-helm";
nodes.machine =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
kubectl
yq-go
];
environment.sessionVariables.KUBECONFIG = "/etc/rancher/${rancherDistro}/${rancherDistro}.yaml";
virtualisation = vmResources;
services.${rancherDistro} = {
enable = true;
package = rancherPackage;
disable =
{
k3s = lib.remove "traefik" disabledComponents;
rke2 = lib.remove "rke2-ingress-nginx" disabledComponents;
}
.${rancherDistro};
images =
coreImages
# Provides the k3s Helm controller
++ lib.optional (rancherDistro == "k3s") rancherPackage.airgap-images
++ [
testImage
];
autoDeployCharts = {
# regular test chart that should get installed
hello = testChart;
# disabled chart that should not get installed
disabled = testChart // {
enable = false;
};
# chart with values set via YAML file
values-file = testChart // {
# Remove unsafeDiscardStringContext workaround when Nix can convert a string to a path
# https://github.com/NixOS/nix/issues/12407
values =
/.
+ builtins.unsafeDiscardStringContext (
builtins.toFile "${rancherDistro}-test-chart-values.yaml" ''
runCommand: "echo 'Hello, file!'"
image:
repository: test.local/test
tag: local
''
);
};
# advanced chart that should get installed in the "test" namespace with a custom
# timeout and overridden values
advanced = testChart // {
# create the "test" namespace via extraDeploy for testing
extraDeploy = [
{
apiVersion = "v1";
kind = "Namespace";
metadata.name = "test";
}
];
extraFieldDefinitions = {
spec = {
# overwrite chart values
valuesContent = ''
runCommand: "echo 'advanced hello'"
image:
repository: ${testImage.imageName}
tag: ${testImage.imageTag}
'';
# overwrite the chart namespace
targetNamespace = "test";
# set a custom timeout
timeout = "69s";
};
};
};
};
};
};
testScript = # python
let
manifestFormat =
{
k3s = "yaml";
rke2 = "json";
}
.${rancherDistro};
in
''
import json
machine.wait_for_unit("${serviceName}")
# check existence/absence of chart manifest files
machine.succeed("test -e /var/lib/rancher/${rancherDistro}/server/manifests/hello.${manifestFormat}")
machine.succeed("test ! -e /var/lib/rancher/${rancherDistro}/server/manifests/disabled.${manifestFormat}")
machine.succeed("test -e /var/lib/rancher/${rancherDistro}/server/manifests/values-file.${manifestFormat}")
machine.succeed("test -e /var/lib/rancher/${rancherDistro}/server/manifests/advanced.${manifestFormat}")
# check that the timeout is set correctly, select only the first item in advanced.yaml
advancedManifest = json.loads(machine.succeed("yq -o json '.items[0]' /var/lib/rancher/${rancherDistro}/server/manifests/advanced.${manifestFormat}"))
t.assertEqual(advancedManifest["spec"]["timeout"], "69s", "unexpected value for spec.timeout")
# wait for test jobs to complete
machine.wait_until_succeeds("kubectl wait --for=condition=complete job/hello", timeout=180)
machine.wait_until_succeeds("kubectl wait --for=condition=complete job/values-file", timeout=180)
machine.wait_until_succeeds("kubectl -n test wait --for=condition=complete job/advanced", timeout=180)
# check output of test jobs
hello_output = machine.succeed("kubectl logs -l batch.kubernetes.io/job-name=hello")
values_file_output = machine.succeed("kubectl logs -l batch.kubernetes.io/job-name=values-file")
advanced_output = machine.succeed("kubectl -n test logs -l batch.kubernetes.io/job-name=advanced")
# strip the output to remove trailing whitespaces
t.assertEqual(hello_output.rstrip(), "Hello, world!", "unexpected output of hello job")
t.assertEqual(values_file_output.rstrip(), "Hello, file!", "unexpected output of values file job")
t.assertEqual(advanced_output.rstrip(), "advanced hello", "unexpected output of advanced job")
# wait for bundled ingress deployment
${
{
k3s = ''
machine.wait_until_succeeds("kubectl -n kube-system rollout status deployment traefik", timeout=180)
'';
rke2 = ''
machine.wait_until_succeeds("kubectl -n kube-system rollout status daemonset rke2-ingress-nginx-controller", timeout=180)
'';
}
.${rancherDistro}
}
'';
meta.maintainers = lib.teams.k3s.members ++ pkgs.rke2.meta.maintainers;
}
+134
View File
@@ -0,0 +1,134 @@
# Tests whether container images are imported and auto deploying manifests work
{
pkgs,
lib,
rancherDistro,
rancherPackage,
serviceName,
disabledComponents,
coreImages,
vmResources,
...
}:
let
pauseImageEnv = pkgs.buildEnv {
name = "${rancherDistro}-pause-image-env";
paths = with pkgs; [
tini
(lib.hiPrio coreutils)
busybox
];
};
pauseImage = pkgs.dockerTools.buildImage {
name = "test.local/pause";
tag = "local";
copyToRoot = pauseImageEnv;
config.Entrypoint = [
"/bin/tini"
"--"
"/bin/sleep"
"inf"
];
};
helloImage = pkgs.dockerTools.buildImage {
name = "test.local/hello";
tag = "local";
copyToRoot = pkgs.hello;
config.Entrypoint = [ "${pkgs.hello}/bin/hello" ];
};
manifestFormat =
{
k3s = "yaml";
rke2 = "json";
}
.${rancherDistro};
in
{
name = "${rancherPackage.name}-auto-deploy";
nodes.machine =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
kubectl
cri-tools
];
environment.sessionVariables.KUBECONFIG = "/etc/rancher/${rancherDistro}/${rancherDistro}.yaml";
virtualisation = vmResources;
services.${rancherDistro} = {
enable = true;
role = "server";
package = rancherPackage;
disable = disabledComponents;
extraFlags = [
"--pause-image test.local/pause:local"
];
images = coreImages ++ [
pauseImage
helloImage
];
manifests = {
absent = {
enable = false;
content = {
apiVersion = "v1";
kind = "Namespace";
metadata.name = "absent";
};
};
present = {
target = "foo-namespace.${manifestFormat}";
content = {
apiVersion = "v1";
kind = "Namespace";
metadata.name = "foo";
};
};
hello.content = {
apiVersion = "batch/v1";
kind = "Job";
metadata.name = "hello";
spec = {
template.spec = {
containers = [
{
name = "hello";
image = "test.local/hello:local";
}
];
restartPolicy = "OnFailure";
};
};
};
};
};
};
testScript = # python
''
start_all()
machine.wait_for_unit("${serviceName}")
# check existence of the manifest files
machine.fail("ls /var/lib/rancher/${rancherDistro}/server/manifests/absent.${manifestFormat}")
machine.succeed("ls /var/lib/rancher/${rancherDistro}/server/manifests/foo-namespace.${manifestFormat}")
machine.succeed("ls /var/lib/rancher/${rancherDistro}/server/manifests/hello.${manifestFormat}")
# check if container images got imported
# for some reason, RKE2 also uses /run/k3s
machine.wait_until_succeeds("crictl -r /run/k3s/containerd/containerd.sock img | grep 'test\.local/pause'")
machine.wait_until_succeeds("crictl -r /run/k3s/containerd/containerd.sock img | grep 'test\.local/hello'")
# check if resources of manifests got created
machine.wait_until_succeeds("kubectl get ns foo")
machine.wait_until_succeeds("kubectl wait --for=condition=complete job/hello")
machine.fail("kubectl get ns absent")
'';
meta.maintainers = lib.teams.k3s.members ++ pkgs.rke2.meta.maintainers;
}
+59
View File
@@ -0,0 +1,59 @@
# A test that containerdConfigTemplate settings get written to containerd/config.toml
{
pkgs,
lib,
rancherDistro,
rancherPackage,
serviceName,
disabledComponents,
coreImages,
vmResources,
...
}:
let
nodeName = "test";
in
{
name = "${rancherPackage.name}-containerd-config";
nodes.machine =
{ ... }:
{
environment.systemPackages = with pkgs; [
kubectl
jq
];
environment.sessionVariables.KUBECONFIG = "/etc/rancher/${rancherDistro}/${rancherDistro}.yaml";
virtualisation = vmResources;
services.${rancherDistro} = {
enable = true;
package = rancherPackage;
disable = disabledComponents;
images = coreImages;
inherit nodeName;
containerdConfigTemplate = ''
# Base ${rancherDistro} config
{{ template "base" . }}
# MAGIC COMMENT
'';
};
};
testScript = # python
''
start_all()
machine.wait_for_unit("${serviceName}")
# wait until the node is ready
machine.wait_until_succeeds(r"""kubectl get node ${nodeName} -ojson | jq -e '.status.conditions[] | select(.type == "Ready") | .status == "True"'""")
# test whether the config template file contains the magic comment
out=machine.succeed("cat /var/lib/rancher/${rancherDistro}/agent/etc/containerd/config.toml.tmpl")
t.assertIn("MAGIC COMMENT", out, "the containerd config template does not contain the magic comment")
# test whether the config file contains the magic comment
out=machine.succeed("cat /var/lib/rancher/${rancherDistro}/agent/etc/containerd/config.toml")
t.assertIn("MAGIC COMMENT", out, "the containerd config does not contain the magic comment")
'';
meta.maintainers = lib.teams.k3s.members ++ pkgs.rke2.meta.maintainers;
}
+116
View File
@@ -0,0 +1,116 @@
{
runTest,
pkgs,
lib,
# service/package name to test
rancherDistro,
...
}:
let
allPackages = lib.filterAttrs (
name: package:
builtins.match "^${rancherDistro}(_[[:digit:]]+)+$" name != null
&& (builtins.tryEval package).success
) pkgs;
allTests =
let
mkTestArgs = rancherPackage: {
inherit rancherDistro rancherPackage;
# systemd service name
serviceName =
{
k3s = "k3s";
rke2 = "rke2-server";
}
.${rancherDistro};
# list passed to services.*.disable,
# for slightly reduced resource usage
disabledComponents =
{
k3s = [
"coredns"
"local-storage"
"metrics-server"
"servicelb"
"traefik"
];
rke2 = [
"rke2-coredns"
"rke2-metrics-server"
"rke2-ingress-nginx"
"rke2-snapshot-controller"
"rke2-snapshot-controller-crd"
"rke2-snapshot-validation-webhook"
];
}
.${rancherDistro};
# images that must be present for all tests
coreImages =
{
k3s = [ ];
rke2 =
{
aarch64-linux = [
rancherPackage.images-core-linux-arm64-tar-zst
rancherPackage.images-canal-linux-arm64-tar-zst
];
x86_64-linux = [
rancherPackage.images-core-linux-amd64-tar-zst
rancherPackage.images-canal-linux-amd64-tar-zst
];
}
.${pkgs.stdenv.hostPlatform.system}
or (throw "RKE2: Unsupported system: ${pkgs.stdenv.hostPlatform.system}");
}
.${rancherDistro};
# virtualization.* attrs, since all distros
# need more resources than the default
vmResources =
{
k3s = {
memorySize = 1536;
diskSize = 4096;
};
rke2 = {
cores = 4;
memorySize = 4096;
diskSize = 8092;
};
}
.${rancherDistro};
};
mkTests =
path:
lib.mapAttrs (
name: package:
runTest {
imports = [ path ];
_module.args = mkTestArgs package;
}
) allPackages;
in
{
airgap-images = mkTests ./airgap-images.nix;
auto-deploy = mkTests ./auto-deploy.nix;
auto-deploy-charts = mkTests ./auto-deploy-charts.nix;
containerd-config = mkTests ./containerd-config.nix;
etcd = mkTests ./etcd.nix;
kubelet-config = mkTests ./kubelet-config.nix;
multi-node = mkTests ./multi-node.nix;
single-node = mkTests ./single-node.nix;
};
in
allTests
// {
all = lib.concatMapAttrs (
testType: lib.mapAttrs' (package: lib.nameValuePair "${testType}-${package}")
) allTests;
}
+129
View File
@@ -0,0 +1,129 @@
# Tests K3s with Etcd backend
{
pkgs,
lib,
rancherDistro,
rancherPackage,
serviceName,
disabledComponents,
coreImages,
vmResources,
...
}:
{
name = "${rancherPackage.name}-etcd";
nodes = {
etcd =
{ ... }:
{
services.etcd = {
enable = true;
openFirewall = true;
listenClientUrls = [
"http://192.168.1.1:2379"
"http://127.0.0.1:2379"
];
listenPeerUrls = [ "http://192.168.1.1:2380" ];
initialAdvertisePeerUrls = [ "http://192.168.1.1:2380" ];
initialCluster = [ "etcd=http://192.168.1.1:2380" ];
};
networking = {
useDHCP = false;
defaultGateway = "192.168.1.1";
interfaces.eth1.ipv4.addresses = pkgs.lib.mkForce [
{
address = "192.168.1.1";
prefixLength = 24;
}
];
};
};
server =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
kubectl
jq
];
environment.sessionVariables.KUBECONFIG = "/etc/rancher/${rancherDistro}/${rancherDistro}.yaml";
virtualisation = vmResources;
services.${rancherDistro} = {
enable = true;
role = "server";
package = rancherPackage;
disable = disabledComponents;
images = coreImages;
nodeIP = "192.168.1.2";
extraFlags = [
"--datastore-endpoint=\"http://192.168.1.1:2379\""
];
};
networking = {
firewall = {
allowedTCPPorts = [
2379
2380
6443
];
allowedUDPPorts = [ 8472 ];
};
useDHCP = false;
defaultGateway = "192.168.1.2";
interfaces.eth1.ipv4.addresses = pkgs.lib.mkForce [
{
address = "192.168.1.2";
prefixLength = 24;
}
];
};
};
};
testScript = # python
''
with subtest("should start etcd"):
etcd.start()
etcd.wait_for_unit("etcd.service")
with subtest("should wait for etcdctl endpoint status to succeed"):
etcd.wait_until_succeeds("etcdctl endpoint status")
with subtest("should wait for etcdctl endpoint health to succeed"):
etcd.wait_until_succeeds("etcdctl endpoint health")
with subtest("should start ${rancherDistro}"):
server.start()
server.wait_for_unit("${serviceName}")
with subtest("should test if kubectl works"):
server.wait_until_succeeds("kubectl get node")
with subtest("should wait for service account to show up; takes a sec"):
server.wait_until_succeeds("kubectl get serviceaccount default")
with subtest("should create a sample secret object"):
server.succeed("kubectl create secret generic nixossecret --from-literal thesecret=abacadabra")
with subtest("should check if secret is correct"):
server.wait_until_succeeds("[[ $(kubectl get secrets nixossecret -o json | jq -r .data.thesecret | base64 -d) == abacadabra ]]")
with subtest("should have a secret in database"):
etcd.wait_until_succeeds("[[ $(etcdctl get /registry/secrets/default/nixossecret | head -c1 | wc -c) -ne 0 ]]")
with subtest("should delete the secret"):
server.succeed("kubectl delete secret nixossecret")
with subtest("should not have a secret in database"):
etcd.wait_until_fails("[[ $(etcdctl get /registry/secrets/default/nixossecret | head -c1 | wc -c) -ne 0 ]]")
'';
meta.maintainers =
pkgs.etcd.meta.maintainers ++ lib.teams.k3s.members ++ pkgs.rke2.meta.maintainers;
}
+75
View File
@@ -0,0 +1,75 @@
# A test that sets extra kubelet configuration and enables graceful node shutdown
{
pkgs,
lib,
rancherDistro,
rancherPackage,
serviceName,
disabledComponents,
coreImages,
vmResources,
...
}:
let
nodeName = "test";
shutdownGracePeriod = "1m13s";
shutdownGracePeriodCriticalPods = "13s";
podsPerCore = 3;
memoryThrottlingFactor = 0.69;
containerLogMaxSize = "5Mi";
in
{
name = "${rancherPackage.name}-kubelet-config";
nodes.machine =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
kubectl
jq
];
environment.sessionVariables.KUBECONFIG = "/etc/rancher/${rancherDistro}/${rancherDistro}.yaml";
virtualisation = vmResources;
services.${rancherDistro} = {
enable = true;
package = rancherPackage;
disable = disabledComponents;
images = coreImages;
inherit nodeName;
gracefulNodeShutdown = {
enable = true;
inherit shutdownGracePeriod shutdownGracePeriodCriticalPods;
};
extraKubeletConfig = {
inherit podsPerCore memoryThrottlingFactor containerLogMaxSize;
};
};
};
testScript = # python
''
import json
start_all()
machine.wait_for_unit("${serviceName}")
# wait until the node is ready
machine.wait_until_succeeds(r"""kubectl get node ${nodeName} -ojson | jq -e '.status.conditions[] | select(.type == "Ready") | .status == "True"'""")
# test whether the kubelet registered an inhibitor lock
machine.succeed("systemd-inhibit --list --no-legend | grep \"^kubelet.*shutdown\"")
# run kubectl proxy in the background, close stdout through redirection to not wait for the command to finish
machine.execute("kubectl proxy --address 127.0.0.1 --port=8001 >&2 &")
machine.wait_until_succeeds("nc -z 127.0.0.1 8001")
# get the kubeletconfig
kubelet_config=json.loads(machine.succeed("curl http://127.0.0.1:8001/api/v1/nodes/${nodeName}/proxy/configz | jq '.kubeletconfig'"))
with subtest("Kubelet config values are set correctly"):
t.assertEqual(kubelet_config["shutdownGracePeriod"], "${shutdownGracePeriod}")
t.assertEqual(kubelet_config["shutdownGracePeriodCriticalPods"], "${shutdownGracePeriodCriticalPods}")
t.assertEqual(kubelet_config["podsPerCore"], ${toString podsPerCore})
t.assertEqual(kubelet_config["memoryThrottlingFactor"], ${toString memoryThrottlingFactor})
t.assertEqual(kubelet_config["containerLogMaxSize"],"${containerLogMaxSize}")
'';
meta.maintainers = lib.teams.k3s.members ++ pkgs.rke2.meta.maintainers;
}
+250
View File
@@ -0,0 +1,250 @@
# A test that runs a multi-node rancher cluster and verifies pod networking works across nodes
{
pkgs,
lib,
rancherDistro,
rancherPackage,
serviceName,
disabledComponents,
coreImages,
vmResources,
...
}:
let
imageEnv = pkgs.buildEnv {
name = "${rancherDistro}-pause-image-env";
paths = with pkgs; [
tini
bashInteractive
coreutils
socat
];
};
pauseImage = pkgs.dockerTools.buildImage {
name = "test.local/pause";
tag = "local";
copyToRoot = imageEnv;
config.Entrypoint = [
"/bin/tini"
"--"
"/bin/sleep"
"inf"
];
};
# A daemonset that responds 'server' on port 8000
networkTestDaemonset = pkgs.writeText "test.yml" ''
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: test
labels:
name: test
spec:
selector:
matchLabels:
name: test
template:
metadata:
labels:
name: test
spec:
containers:
- name: test
image: test.local/pause:local
imagePullPolicy: Never
resources:
limits:
memory: 20Mi
command: ["socat", "TCP4-LISTEN:8000,fork", "EXEC:echo server"]
'';
tokenFile = pkgs.writeText "token" "p@s$w0rd";
supervisorPort =
{
k3s = "6443";
rke2 = "9345";
}
.${rancherDistro};
in
{
name = "${rancherPackage.name}-multi-node";
nodes = {
server =
{
nodes,
pkgs,
config,
...
}:
{
environment.systemPackages = with pkgs; [
kubectl
gzip
jq
];
environment.sessionVariables.KUBECONFIG = "/etc/rancher/${rancherDistro}/${rancherDistro}.yaml";
virtualisation = vmResources;
services.${rancherDistro} = lib.mkMerge [
{
inherit tokenFile;
enable = true;
role = "server";
package = rancherPackage;
images = coreImages ++ [ pauseImage ];
nodeIP = config.networking.primaryIPAddress;
disable = disabledComponents;
extraFlags = [
"--pause-image test.local/pause:local"
];
}
{
k3s = {
clusterInit = true;
extraFlags = [ "--flannel-iface eth1" ]; # see canalConfig definition
};
# The interface selection logic of flannel & canal would normally use eth0, as
# the nixos testing driver sets a default route via dev eth0. However, in test
# setups we have to use eth1 for inter-node communication.
# For K3s this can be handled via --flannel-iface, but RKE2's canal has to be
# configured with this manifest.
rke2.manifests.canal-config.content = {
apiVersion = "helm.cattle.io/v1";
kind = "HelmChartConfig";
metadata = {
name = "rke2-canal";
namespace = "kube-system";
};
# spec.valuesContent needs to a string, either json or yaml
spec.valuesContent = builtins.toJSON {
flannel.iface = "eth1";
};
};
}
.${rancherDistro}
];
networking.firewall.enable = false;
networking.firewall.allowedTCPPorts = [
2379
2380
6443
]
++ lib.optionals (rancherDistro == "rke2") [
9099
9345
];
networking.firewall.allowedUDPPorts = [ 8472 ];
};
server2 =
{
nodes,
pkgs,
config,
...
}:
{
virtualisation = vmResources;
services.${rancherDistro} = {
inherit tokenFile;
enable = true;
role = "server";
package = rancherPackage;
images = coreImages ++ [ pauseImage ];
serverAddr = "https://${nodes.server.networking.primaryIPAddress}:${supervisorPort}";
nodeIP = config.networking.primaryIPAddress;
disable = disabledComponents;
extraFlags = [
"--pause-image test.local/pause:local"
]
++ lib.optional (rancherDistro == "k3s") "--flannel-iface eth1";
};
networking.firewall.enable = false;
networking.firewall.allowedTCPPorts = [
2379
2380
6443
]
++ lib.optionals (rancherDistro == "rke2") [
9099
9345
];
networking.firewall.allowedUDPPorts = [ 8472 ];
};
agent =
{
nodes,
pkgs,
config,
...
}:
{
virtualisation = vmResources;
services.${rancherDistro} = {
inherit tokenFile;
enable = true;
role = "agent";
package = rancherPackage;
images = coreImages ++ [ pauseImage ];
serverAddr = "https://${nodes.server2.networking.primaryIPAddress}:${supervisorPort}";
nodeIP = config.networking.primaryIPAddress;
extraFlags = [
"--pause-image test.local/pause:local"
]
++ lib.optional (rancherDistro == "k3s") "--flannel-iface eth1";
};
networking.firewall.allowedTCPPorts = lib.optional (rancherDistro == "rke2") 9099;
networking.firewall.allowedUDPPorts = [ 8472 ];
};
};
testScript = # python
''
start_all()
servers = [server, server2]
for m in servers:
m.wait_for_unit("${serviceName}")
# wait for the agent to show up
server.wait_until_succeeds("kubectl get node agent")
${lib.optionalString (rancherDistro == "k3s") ''
for m in machines:
m.succeed("k3s check-config")
''}
server.succeed("kubectl cluster-info")
# Also wait for our service account to show up; it takes a sec
server.wait_until_succeeds("kubectl get serviceaccount default")
# Now create a pod on each node via a daemonset and verify they can talk to each other.
server.succeed("kubectl apply -f ${networkTestDaemonset}")
server.wait_until_succeeds(f'[ "$(kubectl get ds test -o json | jq .status.numberReady)" -eq {len(machines)} ]')
# Get pod IPs
pods = server.succeed("kubectl get po -o json | jq '.items[].metadata.name' -r").splitlines()
pod_ips = [server.succeed(f"kubectl get po {name} -o json | jq '.status.podIP' -cr").strip() for name in pods]
# Verify each server can ping each pod ip
for pod_ip in pod_ips:
server.succeed(f"ping -c 1 {pod_ip}")
server2.succeed(f"ping -c 1 {pod_ip}")
agent.succeed(f"ping -c 1 {pod_ip}")
# Verify the pods can talk to each other
for pod in pods:
resp = server.succeed(f"kubectl exec {pod} -- socat TCP:{pod_ip}:8000 -")
t.assertEqual(resp.strip(), "server")
'';
meta.maintainers = lib.teams.k3s.members ++ pkgs.rke2.meta.maintainers;
}
+114
View File
@@ -0,0 +1,114 @@
# A test that runs a single node rancher cluster and verifies a pod can run
{
pkgs,
lib,
rancherDistro,
rancherPackage,
serviceName,
disabledComponents,
coreImages,
vmResources,
...
}:
let
imageEnv = pkgs.buildEnv {
name = "${rancherDistro}-pause-image-env";
paths = with pkgs; [
tini
(lib.hiPrio coreutils)
busybox
];
};
pauseImage = pkgs.dockerTools.buildLayeredImage {
name = "test.local/pause";
tag = "local";
contents = imageEnv;
config.Entrypoint = [
"/bin/tini"
"--"
"/bin/sleep"
"inf"
];
};
testPodYaml = pkgs.writeText "test.yaml" ''
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- name: test
image: test.local/pause:local
imagePullPolicy: Never
command: ["sh", "-c", "sleep inf"]
'';
in
{
name = "${rancherPackage.name}-single-node";
nodes.machine =
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
kubectl
gzip
];
environment.sessionVariables.KUBECONFIG = "/etc/rancher/${rancherDistro}/${rancherDistro}.yaml";
virtualisation = vmResources;
services.${rancherDistro} = {
enable = true;
role = "server";
package = rancherPackage;
disable = disabledComponents;
images = coreImages ++ [ pauseImage ];
extraFlags = [
"--pause-image test.local/pause:local"
];
};
users.users = {
noprivs = {
isNormalUser = true;
description = "Can't access ${rancherDistro} by default";
password = "*";
};
};
};
testScript = # python
''
start_all()
machine.wait_for_unit("${serviceName}")
machine.succeed("kubectl cluster-info")
machine.fail("sudo -u noprivs kubectl cluster-info")
${lib.optionalString (rancherDistro == "k3s") ''
machine.succeed("k3s check-config")
''}
# Also wait for our service account to show up; it takes a sec
machine.wait_until_succeeds("kubectl get serviceaccount default")
machine.succeed("kubectl apply -f ${testPodYaml}")
machine.succeed("kubectl wait --for 'condition=Ready' pod/test --timeout=180s")
machine.succeed("kubectl delete -f ${testPodYaml}")
# regression test for #176445
machine.fail("journalctl -o cat -u ${serviceName}.service | grep 'ipset utility not found'")
with subtest("Run ${rancherDistro}-killall"):
# Call the killall script with a clean path to assert that
# all required commands are wrapped
output = machine.succeed("PATH= ${rancherPackage}/bin/${rancherDistro}-killall.sh 2>&1 | tee /dev/stderr")
t.assertNotIn("command not found", output, "killall script contains unknown command")
# Check that killall cleaned up properly
machine.fail("systemctl is-active ${serviceName}.service")
machine.wait_until_fails("systemctl list-units | grep containerd", timeout=5)
machine.fail("ip link show | awk -F': ' '{print $2}' | grep -e flannel -e cni0")
machine.fail("ip netns show | grep cni-")
'';
meta.maintainers = lib.teams.k3s.members ++ pkgs.rke2.meta.maintainers;
}
-14
View File
@@ -1,14 +0,0 @@
{
system ? builtins.currentSystem,
pkgs ? import ../../.. { inherit system; },
lib ? pkgs.lib,
}:
let
allRKE2 = lib.filterAttrs (n: _: lib.strings.hasPrefix "rke2" n) pkgs;
in
{
# Run a single node rke2 cluster and verify a pod can run
singleNode = lib.mapAttrs (_: rke2: import ./single-node.nix { inherit system pkgs rke2; }) allRKE2;
# Run a multi-node rke2 cluster and verify pod networking works across nodes
multiNode = lib.mapAttrs (_: rke2: import ./multi-node.nix { inherit system pkgs rke2; }) allRKE2;
}
-207
View File
@@ -1,207 +0,0 @@
import ../make-test-python.nix (
{
pkgs,
lib,
rke2,
...
}:
let
throwSystem = throw "RKE2: Unsupported system: ${pkgs.stdenv.hostPlatform.system}";
coreImages =
{
aarch64-linux = rke2.images-core-linux-arm64-tar-zst;
x86_64-linux = rke2.images-core-linux-amd64-tar-zst;
}
.${pkgs.stdenv.hostPlatform.system} or throwSystem;
canalImages =
{
aarch64-linux = rke2.images-canal-linux-arm64-tar-zst;
x86_64-linux = rke2.images-canal-linux-amd64-tar-zst;
}
.${pkgs.stdenv.hostPlatform.system} or throwSystem;
helloImage = pkgs.dockerTools.buildImage {
name = "test.local/hello";
tag = "local";
compressor = "zstd";
copyToRoot = pkgs.buildEnv {
name = "rke2-hello-image-env";
paths = with pkgs; [
coreutils
socat
];
};
};
tokenFile = pkgs.writeText "token" "p@s$w0rd";
agentTokenFile = pkgs.writeText "agent-token" "agentP@s$w0rd";
# Let flannel use eth1 to enable inter-node communication in tests
canalConfig = {
apiVersion = "helm.cattle.io/v1";
kind = "HelmChartConfig";
metadata = {
name = "rke2-canal";
namespace = "kube-system";
};
# spec.valuesContent needs to a string, either json or yaml
spec.valuesContent = builtins.toJSON {
flannel.iface = "eth1";
};
};
in
{
name = "${rke2.name}-multi-node";
meta.maintainers = rke2.meta.maintainers;
nodes = {
server =
{
config,
nodes,
pkgs,
...
}:
{
# Canal CNI with VXLAN
networking.firewall.allowedUDPPorts = [ 8472 ];
networking.firewall.allowedTCPPorts = [
# Kubernetes API
6443
# Canal CNI health checks
9099
# RKE2 supervisor API
9345
];
# RKE2 needs more resources than the default
virtualisation.cores = 4;
virtualisation.memorySize = 4096;
virtualisation.diskSize = 8092;
services.rke2 = {
enable = true;
role = "server";
package = rke2;
inherit tokenFile;
inherit agentTokenFile;
# Without nodeIP the apiserver starts with the wrong service IP family
nodeIP = config.networking.primaryIPAddress;
disable = [
"rke2-coredns"
"rke2-metrics-server"
"rke2-ingress-nginx"
"rke2-snapshot-controller"
"rke2-snapshot-controller-crd"
"rke2-snapshot-validation-webhook"
];
images = [
coreImages
canalImages
helloImage
];
manifests = {
canal-config.content = canalConfig;
# A daemonset that responds 'hello' on port 8000
network-test.content = {
apiVersion = "apps/v1";
kind = "DaemonSet";
metadata = {
name = "test";
labels.name = "test";
};
spec = {
selector.matchLabels.name = "test";
template = {
metadata.labels.name = "test";
spec.containers = [
{
name = "hello";
image = "${helloImage.imageName}:${helloImage.imageTag}";
imagePullPolicy = "Never";
command = [
"socat"
"TCP4-LISTEN:8000,fork"
"EXEC:echo hello"
];
}
];
};
};
};
};
};
};
agent =
{
config,
nodes,
pkgs,
...
}:
{
# Canal CNI health checks
networking.firewall.allowedTCPPorts = [ 9099 ];
# Canal CNI with VXLAN
networking.firewall.allowedUDPPorts = [ 8472 ];
# The agent node can work with less resources
virtualisation.memorySize = 2048;
virtualisation.diskSize = 8092;
services.rke2 = {
enable = true;
role = "agent";
package = rke2;
tokenFile = agentTokenFile;
serverAddr = "https://${nodes.server.networking.primaryIPAddress}:9345";
nodeIP = config.networking.primaryIPAddress;
manifests.canal-config.content = canalConfig;
images = [
coreImages
canalImages
helloImage
];
};
};
};
testScript =
let
kubectl = "${pkgs.kubectl}/bin/kubectl --kubeconfig=/etc/rancher/rke2/rke2.yaml";
jq = "${pkgs.jq}/bin/jq";
in
# python
''
start_all()
server.wait_for_unit("rke2-server")
agent.wait_for_unit("rke2-agent")
# Wait for the agent to be ready
server.wait_until_succeeds(r"""${kubectl} wait --for='jsonpath={.status.conditions[?(@.type=="Ready")].status}=True' nodes/agent""")
server.succeed("${kubectl} cluster-info")
server.wait_until_succeeds("${kubectl} get serviceaccount default")
# Now verify that each daemonset pod can talk to each other.
server.wait_until_succeeds(
f'[ "$(${kubectl} get ds test -o json | ${jq} .status.numberReady)" -eq {len(machines)} ]'
)
# Get pod IPs
pods = server.succeed("${kubectl} get po -o json | ${jq} '.items[].metadata.name' -r").splitlines()
pod_ips = [
server.succeed(f"${kubectl} get po {n} -o json | ${jq} '.status.podIP' -cr").strip() for n in pods
]
# Verify each node can ping each pod ip
for pod_ip in pod_ips:
# The CNI sometimes needs a little time
server.wait_until_succeeds(f"ping -c 1 {pod_ip}", timeout=5)
agent.wait_until_succeeds(f"ping -c 1 {pod_ip}", timeout=5)
# Verify the server can exec into the pod
for pod in pods:
resp = server.succeed(f"${kubectl} exec {pod} -- socat TCP:{pod_ip}:8000 -").strip()
assert resp == "hello", f"Unexpected response from hello daemonset: {resp}"
'';
}
)
-144
View File
@@ -1,144 +0,0 @@
import ../make-test-python.nix (
{
pkgs,
lib,
rke2,
...
}:
let
throwSystem = throw "RKE2: Unsupported system: ${pkgs.stdenv.hostPlatform.system}";
coreImages =
{
aarch64-linux = rke2.images-core-linux-arm64-tar-zst;
x86_64-linux = rke2.images-core-linux-amd64-tar-zst;
}
.${pkgs.stdenv.hostPlatform.system} or throwSystem;
canalImages =
{
aarch64-linux = rke2.images-canal-linux-arm64-tar-zst;
x86_64-linux = rke2.images-canal-linux-amd64-tar-zst;
}
.${pkgs.stdenv.hostPlatform.system} or throwSystem;
helloImage = pkgs.dockerTools.buildImage {
name = "test.local/hello";
tag = "local";
compressor = "zstd";
copyToRoot = pkgs.hello;
config.Entrypoint = [ "${pkgs.hello}/bin/hello" ];
};
# A ConfigMap in regular yaml format
cmFile = (pkgs.formats.yaml { }).generate "rke2-manifest-from-file.yaml" {
apiVersion = "v1";
kind = "ConfigMap";
metadata.name = "from-file";
data.username = "foo-file";
};
in
{
name = "${rke2.name}-single-node";
meta.maintainers = rke2.meta.maintainers;
nodes.machine =
{
config,
nodes,
pkgs,
...
}:
{
# RKE2 needs more resources than the default
virtualisation.cores = 4;
virtualisation.memorySize = 4096;
virtualisation.diskSize = 8092;
services.rke2 = {
enable = true;
role = "server";
package = rke2;
# Without nodeIP the apiserver starts with the wrong service IP family
nodeIP = config.networking.primaryIPAddress;
# Slightly reduce resource consumption
disable = [
"rke2-coredns"
"rke2-metrics-server"
"rke2-ingress-nginx"
"rke2-snapshot-controller"
"rke2-snapshot-controller-crd"
"rke2-snapshot-validation-webhook"
];
images = [
coreImages
canalImages
helloImage
];
manifests = {
test-job.content = {
apiVersion = "batch/v1";
kind = "Job";
metadata.name = "test";
spec.template.spec = {
containers = [
{
name = "hello";
image = "${helloImage.imageName}:${helloImage.imageTag}";
}
];
restartPolicy = "Never";
};
};
disabled = {
enable = false;
content = {
apiVersion = "v1";
kind = "ConfigMap";
metadata.name = "disabled";
data.username = "foo";
};
};
from-file.source = "${cmFile}";
custom-target = {
enable = true;
target = "my-manifest.json";
content = {
apiVersion = "v1";
kind = "ConfigMap";
metadata.name = "custom-target";
data.username = "foo-custom";
};
};
};
};
};
testScript =
let
kubectl = "${pkgs.kubectl}/bin/kubectl --kubeconfig=/etc/rancher/rke2/rke2.yaml";
in
# python
''
start_all()
with subtest("Start cluster"):
machine.wait_for_unit("rke2-server")
machine.succeed("${kubectl} cluster-info")
machine.wait_until_succeeds("${kubectl} get serviceaccount default")
with subtest("Test job completes successfully"):
machine.wait_until_succeeds("${kubectl} wait --for 'condition=complete' job/test")
output = machine.succeed("${kubectl} logs -l batch.kubernetes.io/job-name=test").rstrip()
assert output == "Hello, world!", f"unexpected output of test job: {output}"
with subtest("ConfigMap from-file exists"):
output = machine.succeed("${kubectl} get cm from-file -o=jsonpath='{.data.username}'").rstrip()
assert output == "foo-file", f"Unexpected data in Configmap from-file: {output}"
with subtest("ConfigMap custom-target exists"):
# Check that the file exists at the custom target path
machine.succeed("ls /var/lib/rancher/rke2/server/manifests/my-manifest.json")
output = machine.succeed("${kubectl} get cm custom-target -o=jsonpath='{.data.username}'").rstrip()
assert output == "foo-custom", f"Unexpected data in Configmap custom-target: {output}"
with subtest("Disabled ConfigMap doesn't exist"):
machine.fail("${kubectl} get cm disabled")
'';
}
)
@@ -1,11 +1,11 @@
{
"packageVersion": "145.0.1-2",
"packageVersion": "146.0.1-1",
"source": {
"rev": "145.0.1-2",
"hash": "sha256-yqOl0kPaRdthFHopGsPs4patzTmy0mzGaUg0sab5LG4="
"rev": "146.0.1-1",
"hash": "sha256-MYp0PEAbUSJwrvaXYaie7eXj3XRw/EyGrQvsFdVT/Y0="
},
"firefox": {
"version": "145.0.1",
"hash": "sha512-bgUv7kbDGyaWulQD+QXguUsIzjVFiM1jFdVO4dz/m4KDXWTqWldZbfsYZt0VGKKZZv2qvbTDg4EDNEvS3BjHLQ=="
"version": "146.0.1",
"hash": "sha512-rpW4bkg/6/jf7INHdI3ZBI7X1/hFJQ4HqoBI4rNR2mH288X4O7DQxy4adexhtg5Zu+aWOfDzNTKRD/i/XKBzlA=="
}
}
@@ -469,14 +469,11 @@ buildGoModule (finalAttrs: {
;
tests =
let
mkTests =
version:
let
k3s_version = "k3s_" + lib.replaceStrings [ "." ] [ "_" ] (lib.versions.majorMinor version);
in
lib.mapAttrs (name: value: nixosTests.k3s.${name}.${k3s_version}) nixosTests.k3s;
versionedPackage = "k3s_" + lib.replaceStrings [ "." ] [ "_" ] (lib.versions.majorMinor k3sVersion);
in
mkTests k3sVersion;
lib.mapAttrs (name: _: nixosTests.k3s.${name}.${versionedPackage}) (
lib.filterAttrs (n: _: n != "all") nixosTests.k3s
);
imagesList = throw "k3s.imagesList was removed";
airgapImages = throw "k3s.airgapImages was renamed to k3s.airgap-images";
airgapImagesAmd64 = throw "k3s.airgapImagesAmd64 was renamed to k3s.airgap-images-amd64-tar-zst";
@@ -7,7 +7,7 @@ A K3s maintainer, maintains K3s's:
- [documentation](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/networking/cluster/k3s/README.md)
- [issues](https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+k3s)
- [pull requests](https://github.com/NixOS/nixpkgs/pulls?q=is%3Aopen+is%3Apr+label%3A%226.topic%3A+k3s%22)
- [NixOS tests](https://github.com/NixOS/nixpkgs/tree/master/nixos/tests/k3s)
- [NixOS tests](https://github.com/NixOS/nixpkgs/tree/master/nixos/tests/rancher)
- [NixOS service module](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/cluster/rancher)
- [update script](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/networking/cluster/k3s/update-script.sh) (the process of updating)
- updates (the act of updating) and [r-ryantm bot logs](https://r.ryantm.com/log/k3s/)
@@ -22,6 +22,7 @@ lib:
makeWrapper,
fetchzip,
fetchurl,
versionCheckHook,
# Runtime dependencies
procps,
@@ -42,7 +43,6 @@ lib:
# Testing dependencies
nixosTests,
testers,
}:
buildGoModule (finalAttrs: {
pname = "rke2";
@@ -129,25 +129,19 @@ buildGoModule (finalAttrs: {
go tool nm $out/bin/.rke2-wrapped | grep '_Cfunc__goboringcrypto_' > /dev/null
runHook postInstallCheck
'';
nativeInstallCheckInputs = [ versionCheckHook ];
versionCheckProgramArg = "--version";
passthru = {
inherit updateScript;
tests =
let
moduleTests =
let
package_version =
"rke2_" + lib.replaceStrings [ "." ] [ "_" ] (lib.versions.majorMinor rke2Version);
in
lib.mapAttrs (name: value: nixosTests.rke2.${name}.${package_version}) nixosTests.rke2;
versionedPackage =
"rke2_" + lib.replaceStrings [ "." ] [ "_" ] (lib.versions.majorMinor rke2Version);
in
{
version = testers.testVersion {
package = finalAttrs.finalPackage;
version = "v${finalAttrs.version}";
};
}
// moduleTests;
lib.mapAttrs (name: _: nixosTests.rke2.${name}.${versionedPackage}) (
lib.filterAttrs (n: _: n != "all") nixosTests.rke2
);
}
// (lib.mapAttrs (_: value: fetchurl value) imagesVersions);
@@ -652,13 +652,13 @@
"vendorHash": "sha256-jyfzk3vbgZwHlyiFFw1mhD+us/7WNatUQTGN4WsrfgE="
},
"hashicorp_tfe": {
"hash": "sha256-W0O3J08p6QtQVCqE3AGZbR+19SQVXLbxLkkDhpZhJMM=",
"hash": "sha256-9BrGuvIGs5ztEz2/qBkPqGHeAtPAiWA+3UeoEEOWneM=",
"homepage": "https://registry.terraform.io/providers/hashicorp/tfe",
"owner": "hashicorp",
"repo": "terraform-provider-tfe",
"rev": "v0.71.0",
"rev": "v0.72.0",
"spdx": "MPL-2.0",
"vendorHash": "sha256-dZFjjogCIRzxXgJ/VW/WJY1mCNqoa3Es4q+oXLgcGQg="
"vendorHash": "sha256-P49ShCqu3wU2baUjzq8h30s85eIGdrevgzjbOIN0jp8="
},
"hashicorp_time": {
"hash": "sha256-ZArYfbzbrkxGlL1BRFM7PN3hLzdssIL4COsUBdLVMYY=",
@@ -86,8 +86,8 @@ rec {
thunderbird = thunderbird-latest;
thunderbird-latest = common {
version = "145.0";
sha512 = "f33835e4d740b32d072ac915124d988ef9d4cbe55d7c972c817991d19b64e8bc95b75b503ad3cb9abf4fd1d220fc7cb61720ea84dc49482faa13da1690d7d80e";
version = "146.0.1";
sha512 = "8a3b2de246c7c597574fce596836c7ef7b24bd21573feb15c308003f34b82335ad865aa0f81b24d1669c8023c0448c0e273a63019aab13356b023c2e8adc2c47";
updateScript = callPackage ./update.nix {
attrPath = "thunderbirdPackages.thunderbird-latest";
+5 -9
View File
@@ -37,10 +37,10 @@ lib.extendMkDerivation {
in
if args ? minimalOCamlVersion && lib.versionOlder ocaml.version args.minimalOCamlVersion then
throw "${finalAttrs.pname}-${finalAttrs.version} is not available for OCaml ${ocaml.version}"
throw "${pname}-${version} is not available for OCaml ${ocaml.version}"
else
{
name = "ocaml${ocaml.version}-${finalAttrs.pname}-${finalAttrs.version}";
name = "ocaml${ocaml.version}-${pname}-${version}";
strictDeps = true;
@@ -58,14 +58,14 @@ lib.extendMkDerivation {
buildPhase =
args.buildPhase or ''
runHook preBuild
dune build -p ${finalAttrs.pname} ''${enableParallelBuilding:+-j $NIX_BUILD_CORES}
dune build -p ${pname} ''${enableParallelBuilding:+-j $NIX_BUILD_CORES}
runHook postBuild
'';
installPhase =
args.installPhase or ''
runHook preInstall
dune install --prefix $out --libdir $OCAMLFIND_DESTDIR ${finalAttrs.pname} \
dune install --prefix $out --libdir $OCAMLFIND_DESTDIR ${pname} \
${
if lib.versionAtLeast Dune.version "2.9" then
"--docdir $out/share/doc --mandir $out/share/man"
@@ -78,15 +78,11 @@ lib.extendMkDerivation {
checkPhase =
args.checkPhase or ''
runHook preCheck
dune runtest -p ${finalAttrs.pname} ''${enableParallelBuilding:+-j $NIX_BUILD_CORES}
dune runtest -p ${pname} ''${enableParallelBuilding:+-j $NIX_BUILD_CORES}
runHook postCheck
'';
meta = (args.meta or { }) // {
# TODO: ocaml.meta.platforms is where the compiler can run
# Package's meta.platforms are where the compiler can target.
#
# See: rustc.targetPlatforms
platforms = args.meta.platforms or ocaml.meta.platforms;
};
};
@@ -0,0 +1,48 @@
From 2e3ea5ab32ed356c45e0a7a8db37924a77a1c949 Mon Sep 17 00:00:00 2001
From: Marcin Serwin <marcin@serwin.dev>
Date: Sat, 20 Dec 2025 12:51:13 +0100
Subject: [PATCH] Fix wcwidth declaration
The wcwidth function is declared in `wchar.h` on POSIX systems which
is not included in the default Autoconf includes. Because of this
HAVE_DECL_WCWIDTH would be configured to 0.
Since C23 functions with no arguments in prototypes are treated as
taking no arguments. This results in mismatched declaration since in
wchar.h the functions is declared as taking wchar_t.
Signed-off-by: Marcin Serwin <marcin@serwin.dev>
---
configure.ac | 2 +-
mbswidth.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 7d756ee..a1ecbe2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -61,7 +61,7 @@ AC_CHECK_HEADER(wchar.h,[
AC_DEFINE(HAVE_WCHAR_H, 1, [Define if you have the <wchar.h> header file.])],
[ac_have_wchar_h=no])
AC_CHECK_FUNCS(mbtowc wcwidth mbrtowc mbsinit,,ac_widec_funcs=no)
-AC_CHECK_DECLS(wcwidth)
+AC_CHECK_DECLS(wcwidth, [], [], [#include <wchar.h>])
AC_CHECK_TYPE(wchar_t,,ac_widec_funcs=no)
if test x$ac_widec_funcs = xyes -a x$ac_have_wchar_h = xyes; then
diff --git a/mbswidth.c b/mbswidth.c
index 031e6b7..54a2cb5 100644
--- a/mbswidth.c
+++ b/mbswidth.c
@@ -63,7 +63,7 @@
# warn "this configure-time declaration test was not run"
#endif
#if !HAVE_DECL_WCWIDTH
-int wcwidth ();
+int wcwidth (wchar_t);
#endif
#ifndef wcwidth
--
2.51.2
+1 -5
View File
@@ -2,7 +2,6 @@
lib,
stdenv,
fetchgit,
fetchpatch,
autoreconfHook,
pkg-config,
ncurses,
@@ -20,10 +19,7 @@ stdenv.mkDerivation (finalAttrs: {
};
patches = [
(fetchpatch {
url = "https://aur.archlinux.org/cgit/aur.git/plain/abook-gcc15.patch?h=abook";
hash = "sha256-+73+USELoby8JvuVOWZe6E+xtdhajnLnDkzD/77QoTo=";
})
./0001-Fix-wcwidth-declaration.patch
];
# error: implicit declaration of function 'isalnum' [-Wimplicit-function-declaration]
+2 -2
View File
@@ -17,10 +17,10 @@
}:
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "archipelago";
version = "0.6.4";
version = "0.6.5";
src = fetchurl {
url = "https://github.com/ArchipelagoMW/Archipelago/releases/download/${finalAttrs.version}/Archipelago_${finalAttrs.version}_linux-x86_64.AppImage";
hash = "sha256-7yzRYLmrOuiubXOu/ljuBsWvphdJ+07v0LJD0Ae8BTQ=";
hash = "sha256-06EFpnMMz+yqqHDuUDw9AMBd0a0Ay7oVkzD4mna7XeM=";
};
dontUnpack = true;
+8
View File
@@ -3,6 +3,7 @@
lib,
binutils,
fetchFromGitHub,
fetchpatch,
cmake,
ninja,
pkg-config,
@@ -121,6 +122,13 @@ stdenv.mkDerivation (finalAttrs: {
./patches/no-cereal.patch
# Cmake 4 support
./patches/cmake.patch
# Fix build with gcc15
# https://github.com/bambulab/BambuStudio/pull/8555
(fetchpatch {
name = "bambu-studio-include-stdint-header.patch";
url = "https://github.com/bambulab/BambuStudio/commit/434752bf643933f22348d78335abe7f60550e736.patch";
hash = "sha256-vWqTM6IHL/gBncLk6gZHw+dFe0sdVuPdUqYeVJUbTis=";
})
];
doCheck = true;
+2 -2
View File
@@ -6,12 +6,12 @@
}:
let
pname = "bazecor";
version = "1.7.0";
version = "1.8.3";
src = appimageTools.extract {
inherit pname version;
src = fetchurl {
url = "https://github.com/Dygmalab/Bazecor/releases/download/v${version}/Bazecor-${version}-x64.AppImage";
hash = "sha256-i+6EBgT8Fv3GN2qwnr+QH9mcDToeQvit52qRt30Y9sM=";
hash = "sha256-OAwHeLLbW+FlKeyxS+MCOTirHCvqZptiYXbeA3l4YJc=";
};
# Workaround for https://github.com/Dygmalab/Bazecor/issues/370
+11 -11
View File
@@ -1,21 +1,21 @@
{
"x86_64-linux": {
"buck2": "sha256-gVOho7p25okvAV8OqXppdtwOOEzqH7VWcJBT4l5CT2U=",
"rust-project": "sha256-HKctvCiXyGFzfHfB3Qj6qR2p46i5vaaZgPg2J827ou4="
"buck2": "sha256-TOgL0pLnNEAhHkKvynnM91kW06K6jZPeJnpSibYg8EU=",
"rust-project": "sha256-s5JY/m+yC3YNHiOxk6D43ZkWdtWLxlI4X72jSFFd3Hc="
},
"x86_64-darwin": {
"buck2": "sha256-wHk/tJJbupMsrcmXXNVXurfLY2TOSssMnuTZ7LNjASY=",
"rust-project": "sha256-ePawMIfltPRK3mJJxI1BvGs6b2vIcgWzW2XTJykUsdI="
"buck2": "sha256-8SvAZ30ZFsamVAheKpa2vzGty1TZECUv+BHeXLlDneQ=",
"rust-project": "sha256-0af+q1s7iEb6dWl4WuNxFbIskTfrHtU2uhatPyAhZNM="
},
"aarch64-linux": {
"buck2": "sha256-Gn/Q2P0Fs93SbOawhzv8Z9DgbrIUlQ+9E3PyCNsV1pk=",
"rust-project": "sha256-Pm5lEIu0hzI5BuA/LuTKjBP8S63jiz1oSB0g9tSETGU="
"buck2": "sha256-Pka0HEEqRsQp2R435duy6gJy/RQXp5lK5Dg9+rfr9L8=",
"rust-project": "sha256-u3b+XscQpNZOo8OTrLSazFZvm496U4nsWti/6TRf8ZA="
},
"aarch64-darwin": {
"buck2": "sha256-XtGs7g64s76AYhpFDbqSuSlblRauxJM0PaAk1MNNgxA=",
"rust-project": "sha256-CkyLLv41iJTKHVB0e355ZO2MV7NzQeiF1gtWEGF5oAY="
"buck2": "sha256-1Fv0LzAZUN/BbcorCBaPBbm8JAzLarhJysLqPT78XEQ=",
"rust-project": "sha256-PQ7WKjzAPT0uRirWzwJPxKr9V1RQajnlXUMnv8SYdso="
},
"version": "2025-08-15",
"preludeGit": "892cb85f5fc3258c7e4f89a836821ec4b8c7ee44",
"preludeFod": "sha256-cyuOMi8x8q9gd6p1obnYYDVPxyONZ+y41AFXvSbUjC0="
"version": "2025-12-01",
"preludeGit": "0a994e0b600f7d035e1ac69f374c0e37e1e19af6",
"preludeFod": "sha256-IQa4VatN5OaDSyoTbAj1tHNBpJV6Ost9RbLxDD23xVQ="
}
+1 -3
View File
@@ -33,9 +33,7 @@
#
# from the root of the nixpkgs git repository, run:
#
# nix-shell maintainers/scripts/update.nix \
# --argstr commit true \
# --argstr package buck2
# nix-shell maintainers/scripts/update.nix --argstr commit true --argstr package buck2
let
+2 -2
View File
@@ -6,14 +6,14 @@
python3Packages.buildPythonApplication rec {
pname = "check-jsonschema";
version = "0.35.0";
version = "0.36.0";
pyproject = true;
src = fetchFromGitHub {
owner = "python-jsonschema";
repo = "check-jsonschema";
tag = version;
hash = "sha256-IiNUgv0XZtTzCJjp/4jyTpw9MAyBFtuf3N4VFqatZVg=";
hash = "sha256-volbCQ0qxd614CDu0GIFKPXF1qSvgf5tTnJ8skcnnTg=";
};
build-system = with python3Packages; [ setuptools ];
+2 -2
View File
@@ -6,13 +6,13 @@
}:
buildGoModule (finalAttrs: {
pname = "cocoon";
version = "0.7.0";
version = "0.7.1";
src = fetchFromGitHub {
owner = "haileyok";
repo = "cocoon";
tag = "v${finalAttrs.version}";
hash = "sha256-/EaTQC5mkil6SeDCRUcwb8Hv68SeCrlgWDphoFrx3Aw=";
hash = "sha256-kYBYdMoo7ToeljiW7AafL5cHzzeuaiL6MFE4Zw5Taqw=";
};
ldflags = [
+3 -3
View File
@@ -15,7 +15,7 @@
let
pname = "decent-sampler";
version = "1.13.12";
version = "1.15.0";
rlkey = "orvjprslmwn0dkfs0ncx6nxnm";
icon = fetchurl {
@@ -28,8 +28,8 @@ let
src = fetchzip {
# dropbox links: https://www.dropbox.com/sh/dwyry6xpy5uut07/AABBJ84bjTTSQWzXGG5TOQpfa\
url = "https://www.dropbox.com/scl/fo/a0i0udw7ggfwnjoi05hh3/AHLHYaQpGY3OwhYqQEd06Po/Decent_Sampler-${version}-Linux-Static-x86_64.tar.gz?rlkey=${rlkey}&dl=0";
hash = "sha256-sLaQd1AATr1mY3qhylQMkOfIIygKNwvf7K4mVqkbe8U=";
url = "https://www.dropbox.com/scl/fo/a0i0udw7ggfwnjoi05hh3/ABn4zZmR24tyJx0xaRS_lXg/Decent_Sampler-${version}-Linux-Static-x86_64.tar.gz?rlkey=${rlkey}&dl=0";
hash = "sha256-A+CBsGUtqXo7KAlx6BjbHGRZww73TlJCI68thicGKiE=";
};
nativeBuildInputs = [ copyDesktopItems ];
@@ -1,29 +0,0 @@
From 7bc49f8edd9a49d675ee5b163ab61b405e2d0258 Mon Sep 17 00:00:00 2001
From: Jan Tojnar <jtojnar@gmail.com>
Date: Thu, 7 Oct 2021 21:42:26 +0200
Subject: [PATCH] Fix build with Vala 0.54
Vala codegen now emits constructor methods so we need to skip @new
so that we can use a custom one from our VAPI overrides.
https://gitlab.gnome.org/GNOME/vala/-/commit/472765b90cd98c1a628975d20005c46352d665f8
---
vapi/Dee-1.0.metadata | 2 ++
1 file changed, 2 insertions(+)
diff --git a/vapi/Dee-1.0.metadata b/vapi/Dee-1.0.metadata
index 7e80de0..793ffd8 100644
--- a/vapi/Dee-1.0.metadata
+++ b/vapi/Dee-1.0.metadata
@@ -1,6 +1,8 @@
GListResultSet skip
GListResultSetClass skip
+Filter
+ .new skip
FilterModel
.filter unowned
Model
--
2.33.0
+3 -8
View File
@@ -14,7 +14,7 @@
gtk-doc,
}:
stdenv.mkDerivation rec {
stdenv.mkDerivation {
pname = "dee";
version = "unstable-2017-06-16";
@@ -26,16 +26,11 @@ stdenv.mkDerivation rec {
src = fetchgit {
url = "https://git.launchpad.net/ubuntu/+source/dee";
rev = "import/1.2.7+17.10.20170616-4ubuntu3";
sha256 = "09blrdj7229vscp4mkg0fabmcvc6jdpamvblrq86rbky7j2nnwlk";
rev = "applied/1.2.7+17.10.20170616-8build1";
hash = "sha256-ttfppqb0t8cOhWaB97uyD9heVZKlBKYF2zD6yRwPyos=";
};
patches = [
"${src}/debian/patches/gtkdocize.patch"
"${src}/debian/patches/strict-prototype.patch"
"${src}/debian/patches/vapi-skip-properties.patch"
./0001-Fix-build-with-Vala-0.54.patch
# Fixes glib 2.62 deprecations
(fetchpatch {
name = "dee-1.2.7-deprecated-g_type_class_add_private.patch";
+9 -9
View File
@@ -6,8 +6,8 @@
pixman,
fetchFromGitHub,
buildNpmPackage,
prisma,
prisma-engines,
prisma_6,
prisma-engines_6,
vips,
pkg-config,
cairo,
@@ -34,9 +34,9 @@ buildNpmPackage {
env.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "1";
env.PRISMA_QUERY_ENGINE_LIBRARY = "${prisma-engines}/lib/libquery_engine.node";
env.PRISMA_QUERY_ENGINE_BINARY = "${prisma-engines}/bin/query-engine";
env.PRISMA_SCHEMA_ENGINE_BINARY = "${prisma-engines}/bin/schema-engine";
env.PRISMA_QUERY_ENGINE_LIBRARY = "${prisma-engines_6}/lib/libquery_engine.node";
env.PRISMA_QUERY_ENGINE_BINARY = "${prisma-engines_6}/bin/query-engine";
env.PRISMA_SCHEMA_ENGINE_BINARY = "${prisma-engines_6}/bin/schema-engine";
env.TURBO_NO_UPDATE_NOTIFIER = "true";
env.TURBO_FORCE = "true";
env.TURBO_REMOTE_CACHE_ENABLED = "false";
@@ -81,11 +81,11 @@ buildNpmPackage {
cat > $out/bin/${pname} <<EOF
#!${bash}/bin/bash
export PKG_CONFIG_PATH=${openssl.dev}/lib/pkgconfig;
export PRISMA_QUERY_ENGINE_LIBRARY=${prisma-engines}/lib/libquery_engine.node
export PRISMA_QUERY_ENGINE_BINARY=${prisma-engines}/bin/query-engine
export PRISMA_SCHEMA_ENGINE_BINARY=${prisma-engines}
export PRISMA_QUERY_ENGINE_LIBRARY=${prisma-engines_6}/lib/libquery_engine.node
export PRISMA_QUERY_ENGINE_BINARY=${prisma-engines_6}/bin/query-engine
export PRISMA_SCHEMA_ENGINE_BINARY=${prisma-engines_6}
cd $out/apps/remix
${prisma}/bin/prisma migrate deploy --schema ../../packages/prisma/schema.prisma
${prisma_6}/bin/prisma migrate deploy --schema ../../packages/prisma/schema.prisma
${nodejs}/bin/node build/server/main.js
EOF
chmod +x $out/bin/${pname}
+8
View File
@@ -2,6 +2,7 @@
lib,
stdenv,
fetchurl,
fetchpatch2,
}:
stdenv.mkDerivation rec {
@@ -13,6 +14,13 @@ stdenv.mkDerivation rec {
sha256 = "1wwj2hlngi8qn2pisvhyfxxs8gyqjlgrrv5lz91w8ly54dlzvs9j";
};
patches = [
(fetchpatch2 {
url = "https://github.com/crigler/dtach/commit/6d80909a8c0fd19717010a3c76fec560f988ca48.patch?full_index=1";
hash = "sha256-v3vToJdSwihiPCSjXjEJghiaynHPTEql3F7URXRjCbM=";
})
];
installPhase = ''
mkdir -p $out/bin
cp dtach $out/bin/dtach
+2 -2
View File
@@ -8,13 +8,13 @@
}:
stdenv.mkDerivation (finalAttrs: {
pname = "fennel-ls";
version = "0.2.2";
version = "0.2.3";
src = fetchFromSourcehut {
owner = "~xerool";
repo = "fennel-ls";
rev = finalAttrs.version;
hash = "sha256-N1530u8Kq7ljdEdTFk0CJJyMLMVX5huQWXjyoMBJN5E=";
hash = "sha256-BU0SkdBjq8kicvACIo3N2gf1UvTmzA3FKSt39Lxp3rs=";
};
buildInputs = [
lua
+2 -2
View File
@@ -38,13 +38,13 @@ assert withRest -> withJson;
stdenv.mkDerivation rec {
pname = "freeradius";
version = "3.2.7";
version = "3.2.8";
src = fetchFromGitHub {
owner = "FreeRADIUS";
repo = "freeradius-server";
tag = "release_${lib.replaceStrings [ "." ] [ "_" ] version}";
hash = "sha256-FG0/quBB5Q/bdYQqkFaZc/BhcIC/n2uVstlIGe4EPvE=";
hash = "sha256-NvcXTT0jp3WR/w+JWcNESg6iNYqIV8QAlM8MxpYkpjs=";
};
nativeBuildInputs = [ autoreconfHook ];
+2 -2
View File
@@ -9,13 +9,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "gambit-project";
version = "16.4.0";
version = "16.4.1";
src = fetchFromGitHub {
owner = "gambitproject";
repo = "gambit";
rev = "v${finalAttrs.version}";
hash = "sha256-fiWGRL7U4A7FKmAvzYt6WjlkOe0jSq3U2VfxPFvc+FA=";
hash = "sha256-jRjL/rQ3k0zdTFCx1S/jdYpijcBx1aV8zsC8mz8aZ3A=";
};
nativeBuildInputs = [ autoreconfHook ] ++ lib.optional withGui wxGTK31;
+8 -8
View File
@@ -5,8 +5,8 @@
nodejs,
faketty,
openssl,
prisma,
prisma-engines,
prisma_6,
prisma-engines_6,
}:
buildNpmPackage rec {
@@ -30,7 +30,7 @@ buildNpmPackage rec {
npmDepsHash = "sha256-KSKqybqVw2BG/WKuVRyNsneLYyedVeyCvNBLIREx7MQ=";
nativeBuildInputs = [
prisma
prisma_6
faketty
];
@@ -67,11 +67,11 @@ buildNpmPackage rec {
--prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ openssl ]} \
${lib.concatStringsSep " " (
lib.mapAttrsToList (name: value: "--set ${name} ${lib.escapeShellArg value}") {
PRISMA_SCHEMA_ENGINE_BINARY = lib.getExe' prisma-engines "schema-engine";
PRISMA_QUERY_ENGINE_BINARY = lib.getExe' prisma-engines "query-engine";
PRISMA_QUERY_ENGINE_LIBRARY = "${prisma-engines}/lib/libquery_engine.node";
PRISMA_INTROSPECTION_ENGINE_BINARY = lib.getExe' prisma-engines "introspection-engine";
PRISMA_FMT_BINARY = lib.getExe' prisma-engines "prisma-fmt";
PRISMA_SCHEMA_ENGINE_BINARY = lib.getExe' prisma-engines_6 "schema-engine";
PRISMA_QUERY_ENGINE_BINARY = lib.getExe' prisma-engines_6 "query-engine";
PRISMA_QUERY_ENGINE_LIBRARY = "${prisma-engines_6}/lib/libquery_engine.node";
PRISMA_INTROSPECTION_ENGINE_BINARY = lib.getExe' prisma-engines_6 "introspection-engine";
PRISMA_FMT_BINARY = lib.getExe' prisma-engines_6 "prisma-fmt";
}
)}
+6 -9
View File
@@ -9,21 +9,18 @@
nix-update-script,
}:
let
rustPlatform.buildRustPackage (finalAttrs: {
pname = "git-igitt";
version = "0.1.18";
in
rustPlatform.buildRustPackage {
inherit pname version;
version = "0.1.19";
src = fetchFromGitHub {
owner = "mlange-42";
repo = "git-igitt";
rev = version;
hash = "sha256-JXEWnekL9Mtw0S3rI5aeO1HB9kJ7bRJDJ6EJ4ATlFeQ=";
rev = "v${finalAttrs.version}";
hash = "sha256-kryC07G/sMMtz1v6EZPYdCunl/CjC4H+jAV3Y91X9Cg=";
};
cargoHash = "sha256-ndxxkYMFHAX6uourCyUpvJYcZCXQ5X2CMX4jTJmNRiQ=";
cargoHash = "sha256-45ME5Uaqa6qKuqvO1ETEVrySiAylPmx30uShQPPGNmY=";
nativeBuildInputs = [ pkg-config ];
@@ -47,4 +44,4 @@ rustPlatform.buildRustPackage {
maintainers = [ lib.maintainers.pinage404 ];
mainProgram = "git-igitt";
};
}
})
+2 -2
View File
@@ -8,13 +8,13 @@
buildGoModule (finalAttrs: {
pname = "hatchet";
version = "0.7.0";
version = "0.7.2";
src = fetchFromGitHub {
owner = "simagix";
repo = "hatchet";
tag = "v${finalAttrs.version}";
hash = "sha256-cpS46HR6hbjDEBeSYsnnumMzkXUYsEU5CAShoIfu8vo=";
hash = "sha256-L7n5qR6Ijs5wC4ITq6at8EznkiKEceUJgYJyeSoWFWY=";
};
vendorHash = "sha256-5YzrxSB/3tKxE1ObAnx1lbIc+Zlufc6wIJuDQqCcRKc=";
+3 -3
View File
@@ -1,7 +1,7 @@
import ./generic.nix {
hash = "sha256-TdJe/vnjSc5ZT5tgZQsQacCVfW5+TKd5cjQLOp8SuZg=";
version = "6.19.1";
vendorHash = "sha256-Dx/AsSvDL/cHS/nRV5invkxgBg4w8jvtZ20LK7tOW14=";
hash = "sha256-nhf7defhiFBHsqfZ6y+NN3TuteII6t8zCvpTsPsO+EE=";
version = "6.20.0";
vendorHash = "sha256-jIOV6vIkptHEuZcD/aS386o2M2AQHTjHngBxFi2tESA=";
patches = [ ];
nixUpdateExtraArgs = [
"--override-filename=pkgs/by-name/in/incus/package.nix"
+2 -2
View File
@@ -8,13 +8,13 @@
buildGoModule rec {
pname = "lazydocker";
version = "0.24.2";
version = "0.24.3";
src = fetchFromGitHub {
owner = "jesseduffield";
repo = "lazydocker";
rev = "v${version}";
sha256 = "sha256-Dw7FBJ78b835iVkV8OrA06CAZ/GRCEXlLg/RfHZXfF0=";
sha256 = "sha256-JbiG3cy+nn9BWJxX43YW+FKmWvsJPtRZ9NdMHtulzcw=";
};
vendorHash = null;
+2 -2
View File
@@ -9,13 +9,13 @@
stdenv.mkDerivation rec {
pname = "libucontext";
version = "1.3.3";
version = "1.5";
src = fetchFromGitHub {
owner = "kaniini";
repo = "libucontext";
rev = "libucontext-${version}";
hash = "sha256-MQCRRyA64MEtPoUtf1tFVbhiMDc4DlepSjMEFcb/Kh4=";
hash = "sha256-asT0pV3s4L4zB2qtDJ+2XYxEP6agIEo1LtCuFeOjpRA=";
};
nativeBuildInputs = [
+10 -10
View File
@@ -15,8 +15,8 @@
openssl,
google-fonts,
playwright-driver,
prisma,
prisma-engines,
prisma_6,
prisma-engines_6,
}:
let
@@ -81,7 +81,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
nativeBuildInputs = [
makeBinaryWrapper
nodejs
prisma
prisma_6
yarnConfigHook
];
@@ -101,9 +101,9 @@ stdenvNoCC.mkDerivation (finalAttrs: {
preBuild = ''
export PRISMA_CLIENT_ENGINE_TYPE='binary'
export PRISMA_QUERY_ENGINE_LIBRARY="${prisma-engines}/lib/libquery_engine.node"
export PRISMA_QUERY_ENGINE_BINARY="${prisma-engines}/bin/query-engine"
export PRISMA_SCHEMA_ENGINE_BINARY="${prisma-engines}/bin/schema-engine"
export PRISMA_QUERY_ENGINE_LIBRARY="${prisma-engines_6}/lib/libquery_engine.node"
export PRISMA_QUERY_ENGINE_BINARY="${prisma-engines_6}/bin/query-engine"
export PRISMA_SCHEMA_ENGINE_BINARY="${prisma-engines_6}/bin/schema-engine"
'';
buildPhase = ''
@@ -151,7 +151,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
${lib.getExe' nodejs "npm"} start --prefix $out/share/linkwarden/apps/worker
else
echo "Starting server"
${lib.getExe prisma} migrate deploy --schema $out/share/linkwarden/packages/prisma/schema.prisma \
${lib.getExe prisma_6} migrate deploy --schema $out/share/linkwarden/packages/prisma/schema.prisma \
&& ${lib.getExe' nodejs "npm"} start --prefix $out/share/linkwarden/apps/web -- -H \$LINKWARDEN_HOST -p \$LINKWARDEN_PORT
fi
" > $out/bin/start.sh
@@ -166,9 +166,9 @@ stdenvNoCC.mkDerivation (finalAttrs: {
]
}" \
--set-default PRISMA_CLIENT_ENGINE_TYPE 'binary' \
--set-default PRISMA_QUERY_ENGINE_LIBRARY "${prisma-engines}/lib/libquery_engine.node" \
--set-default PRISMA_QUERY_ENGINE_BINARY "${prisma-engines}/bin/query-engine" \
--set-default PRISMA_SCHEMA_ENGINE_BINARY "${prisma-engines}/bin/schema-engine" \
--set-default PRISMA_QUERY_ENGINE_LIBRARY "${prisma-engines_6}/lib/libquery_engine.node" \
--set-default PRISMA_QUERY_ENGINE_BINARY "${prisma-engines_6}/bin/query-engine" \
--set-default PRISMA_SCHEMA_ENGINE_BINARY "${prisma-engines_6}/bin/schema-engine" \
--set-default PLAYWRIGHT_LAUNCH_OPTIONS_EXECUTABLE_PATH ${playwright-driver.browsers-chromium}/chromium-*/chrome-linux/chrome \
--set-default LINKWARDEN_CACHE_DIR /var/cache/linkwarden \
--set-default LINKWARDEN_HOST localhost \
+2 -2
View File
@@ -7,13 +7,13 @@
python3Packages.buildPythonApplication rec {
pname = "mcuboot-imgtool";
version = "2.2.0";
version = "2.3.0";
pyproject = true;
src = fetchPypi {
inherit version;
pname = "imgtool";
hash = "sha256-XIc6EYleNtDrmeg2akOjriJwzE9Bnja2k0KJGCVRZM8=";
hash = "sha256-//cuTnk6wOwCpJPBlUhxXMwKI1ivruqhC0nMwuC9EpU=";
};
passthru.updateScript = nix-update-script { };
+2 -2
View File
@@ -18,13 +18,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "neowall";
version = "0.4.4";
version = "0.4.5";
src = fetchFromGitHub {
owner = "1ay1";
repo = "neowall";
tag = "v${finalAttrs.version}";
hash = "sha256-wm9dmWoB+AeygfhPKWYh2Dn1QrXKMJpTcgKPLl0VMTQ=";
hash = "sha256-dgego9hcYCqnky7hvCubOZWHA1HxKDY9E9F/7YIwj+I=";
};
nativeBuildInputs = [
+2 -2
View File
@@ -14,13 +14,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "nixbit";
version = "0.5.4";
version = "0.6.2";
src = fetchFromGitHub {
owner = "pbek";
repo = "nixbit";
tag = "v${finalAttrs.version}";
hash = "sha256-3zDRR8zaO0VViMI8gtAVJvpeNp1C/VNHUNMdqqxFlPY=";
hash = "sha256-Vbv6+d0jUNxI7TP06vIey3a7fCzX/jgnNJZ18ntBN2k=";
};
nativeBuildInputs = [
+219 -127
View File
@@ -1,12 +1,12 @@
{
"name": "node-red",
"version": "4.1.1",
"version": "4.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "node-red",
"version": "4.1.1",
"version": "4.1.2",
"license": "Apache-2.0",
"dependencies": {
"acorn": "8.15.0",
@@ -25,7 +25,7 @@
"cors": "2.8.5",
"cronosjs": "1.7.1",
"denque": "2.1.0",
"express": "4.21.2",
"express": "4.22.1",
"express-session": "1.18.2",
"form-data": "4.0.4",
"fs-extra": "11.3.0",
@@ -36,7 +36,7 @@
"i18next": "24.2.3",
"iconv-lite": "0.6.3",
"is-utf8": "0.2.1",
"js-yaml": "4.1.0",
"js-yaml": "4.1.1",
"json-stringify-safe": "5.0.1",
"jsonata": "2.0.6",
"lodash.clonedeep": "^4.5.0",
@@ -150,14 +150,14 @@
}
},
"node_modules/@babel/generator": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
"integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
"integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.3",
"@babel/types": "^7.28.2",
"@babel/parser": "^7.28.5",
"@babel/types": "^7.28.5",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
@@ -187,9 +187,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -197,13 +197,13 @@
}
},
"node_modules/@babel/parser": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
"integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
"integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.28.4"
"@babel/types": "^7.28.5"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -237,18 +237,18 @@
}
},
"node_modules/@babel/traverse": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
"integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
"integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.5",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.28.4",
"@babel/parser": "^7.28.5",
"@babel/template": "^7.27.2",
"@babel/types": "^7.28.4",
"@babel/types": "^7.28.5",
"debug": "^4.3.1"
},
"engines": {
@@ -281,14 +281,14 @@
"license": "MIT"
},
"node_modules/@babel/types": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
"integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
"integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1"
"@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -346,9 +346,9 @@
"license": "Apache-2.0"
},
"node_modules/@emnapi/core": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
"integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==",
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz",
"integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -357,9 +357,9 @@
}
},
"node_modules/@emnapi/runtime": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
"integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz",
"integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -817,9 +817,9 @@
}
},
"node_modules/@paralleldrive/cuid2": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz",
"integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz",
"integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1242,18 +1242,18 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.8.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.8.1.tgz",
"integrity": "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==",
"version": "24.10.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.14.0"
"undici-types": "~7.16.0"
}
},
"node_modules/@types/readable-stream": {
"version": "4.0.21",
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.21.tgz",
"integrity": "sha512-19eKVv9tugr03IgfXlA9UVUVRbW6IuqRO5B92Dl4a6pT7K8uaGrNS0GkxiZD0BOk6PLuXl5FhWl//eX/pzYdTQ==",
"version": "4.0.22",
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.22.tgz",
"integrity": "sha512-/FFhJpfCLAPwAcN3mFycNUa77ddnr8jTgF5VmSNetaemWB2cIlfCA9t0YTM3JAT0wOcv8D4tjPo7pkDhK3EJIg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
@@ -1831,9 +1831,9 @@
}
},
"node_modules/bl": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/bl/-/bl-6.1.4.tgz",
"integrity": "sha512-ZV/9asSuknOExbM/zPPA8z00lc1ihPKWaStHkkQrxHNeYx+yY+TmF+v80dpv2G0mv3HVXBu7ryoAsxbFFhf4eg==",
"version": "6.1.6",
"resolved": "https://registry.npmjs.org/bl/-/bl-6.1.6.tgz",
"integrity": "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==",
"license": "MIT",
"dependencies": {
"@types/readable-stream": "^4.0.0",
@@ -1938,6 +1938,7 @@
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz",
"integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==",
"deprecated": "No longer maintained. Please upgrade to a stable version.",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3431,9 +3432,9 @@
}
},
"node_modules/dayjs": {
"version": "1.11.18",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
"integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==",
"version": "1.11.19",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
"dev": true,
"license": "MIT"
},
@@ -3977,39 +3978,39 @@
}
},
"node_modules/express": {
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"version": "4.22.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"body-parser": "~1.20.3",
"content-disposition": "~0.5.4",
"content-type": "~1.0.4",
"cookie": "0.7.1",
"cookie-signature": "1.0.6",
"cookie": "~0.7.1",
"cookie-signature": "~1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"finalhandler": "~1.3.1",
"fresh": "~0.5.2",
"http-errors": "~2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"on-finished": "~2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.12",
"path-to-regexp": "~0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"qs": "~6.14.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.19.0",
"serve-static": "1.16.2",
"send": "~0.19.0",
"serve-static": "~1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"statuses": "~2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
@@ -4067,13 +4068,19 @@
],
"license": "MIT"
},
"node_modules/express/node_modules/cookie": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"license": "MIT",
"node_modules/express/node_modules/qs": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">= 0.6"
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/express/node_modules/safe-buffer": {
@@ -4097,9 +4104,9 @@
"license": "MIT"
},
"node_modules/exsolve": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz",
"integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==",
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
"integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==",
"dev": true,
"license": "MIT"
},
@@ -4263,17 +4270,17 @@
}
},
"node_modules/finalhandler": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
"integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"on-finished": "~2.4.1",
"parseurl": "~1.3.3",
"statuses": "2.0.1",
"statuses": "~2.0.2",
"unpipe": "~1.0.0"
},
"engines": {
@@ -5313,9 +5320,9 @@
}
},
"node_modules/grunt/node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5604,6 +5611,15 @@
"node": ">= 0.8"
}
},
"node_modules/http-errors/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/http-parser-js": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
@@ -5827,9 +5843,9 @@
"license": "MIT"
},
"node_modules/ip-address": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
"integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
"integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
"license": "MIT",
"engines": {
"node": ">= 12"
@@ -6229,9 +6245,9 @@
"license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@@ -7323,9 +7339,9 @@
}
},
"node_modules/mermaid/node_modules/marked": {
"version": "16.4.1",
"resolved": "https://registry.npmjs.org/marked/-/marked-16.4.1.tgz",
"integrity": "sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg==",
"version": "16.4.2",
"resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz",
"integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==",
"dev": true,
"license": "MIT",
"bin": {
@@ -7645,6 +7661,19 @@
"node": "*"
}
},
"node_modules/mocha/node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/mocha/node_modules/minimatch": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
@@ -8489,9 +8518,9 @@
}
},
"node_modules/nyc/node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8896,9 +8925,9 @@
}
},
"node_modules/package-manager-detector": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.5.0.tgz",
"integrity": "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz",
"integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==",
"dev": true,
"license": "MIT"
},
@@ -9840,13 +9869,13 @@
}
},
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.0",
"is-core-module": "^2.16.1",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
@@ -10024,10 +10053,10 @@
}
},
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"license": "ISC"
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz",
"integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==",
"license": "BlueOak-1.0.0"
},
"node_modules/semver": {
"version": "7.7.1",
@@ -10042,15 +10071,15 @@
}
},
"node_modules/send": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.1.tgz",
"integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
@@ -10065,15 +10094,6 @@
"node": ">= 0.8.0"
}
},
"node_modules/send/node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/send/node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -10092,6 +10112,15 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/send/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@@ -10117,6 +10146,66 @@
"node": ">= 0.8.0"
}
},
"node_modules/serve-static/node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"license": "MIT",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/serve-static/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/serve-static/node_modules/send": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/serve-static/node_modules/send/node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/serve-static/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -10611,9 +10700,9 @@
"license": "BSD-3-Clause"
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -11136,11 +11225,14 @@
"license": "MIT"
},
"node_modules/tinyexec": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz",
"integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
"integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
"dev": true,
"license": "MIT"
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/tldts": {
"version": "6.1.86",
@@ -11355,9 +11447,9 @@
}
},
"node_modules/undici-types": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
"integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"license": "MIT"
},
"node_modules/universalify": {
+3 -3
View File
@@ -8,16 +8,16 @@
buildNpmPackage rec {
pname = "node-red";
version = "4.1.1";
version = "4.1.2";
src = fetchFromGitHub {
owner = "node-red";
repo = "node-red";
tag = version;
hash = "sha256-guyWY5Bk9mP5WBjPAKGq/Hp4BYF1rDYDG0m1rOLnpio=";
hash = "sha256-Xr00S9Q8EPPGcd3kNHjmqYuzdzN6+W8xVuJsUVr4yII=";
};
npmDepsHash = "sha256-GMbUAdAHrDJZIrUzXtDxW8kP0KZK2GTxsHWxoZTaqAQ=";
npmDepsHash = "sha256-8nwIEu/p5kVYoG3+jXBss352MciCnk/aGV9nbDGHDdA=";
postPatch =
let
@@ -3,7 +3,6 @@
lib,
openssl,
pkg-config,
protobuf,
rustPlatform,
stdenv,
}:
@@ -12,14 +11,14 @@
# version of prisma-engines and prisma must be the same for them to
# function correctly.
rustPlatform.buildRustPackage rec {
pname = "prisma-engines";
version = "6.19.0";
pname = "prisma-engines_6";
version = "6.19.1";
src = fetchFromGitHub {
owner = "prisma";
repo = "prisma-engines";
rev = version;
hash = "sha256-icFgoKIrr3fGSVmSczlMJiT5KSb746kVldtrk+Q0wW8=";
tag = version;
hash = "sha256-z3GdnrLEMJIGPKXXbz2wrbiGpuNlgYxqg3iYINYTnPI=";
};
cargoHash = "sha256-PgCfBcmK9RCA5BMacJ5oYEpo2DnBKx2xPbdLb79yCCY=";
@@ -35,9 +34,6 @@ rustPlatform.buildRustPackage rec {
export OPENSSL_DIR=${lib.getDev openssl}
export OPENSSL_LIB_DIR=${lib.getLib openssl}/lib
export PROTOC=${protobuf}/bin/protoc
export PROTOC_INCLUDE="${protobuf}/include";
export SQLITE_MAX_VARIABLE_NUMBER=250000
export SQLITE_MAX_EXPR_DEPTH=10000
@@ -71,7 +67,6 @@ rustPlatform.buildRustPackage rec {
platforms = lib.platforms.unix;
mainProgram = "prisma";
maintainers = with lib.maintainers; [
tomhoule
aqrln
];
};
@@ -0,0 +1,74 @@
{
fetchFromGitHub,
lib,
openssl,
pkg-config,
rustPlatform,
}:
# Updating this package will force an update for prisma. The
# version of prisma-engines and prisma must be the same for them to
# function correctly.
rustPlatform.buildRustPackage rec {
pname = "prisma-engines_7";
version = "7.0.1";
src = fetchFromGitHub {
owner = "prisma";
repo = "prisma-engines";
tag = version;
hash = "sha256-+8k+M2+WySR2CeywYlhU/jd3av/4UeUoEOlO/qHUk5o=";
};
cargoHash = "sha256-n83hJfSlvuaoBb3w9Rk8+q2emjGCoPDHhFdoVzhf4sM=";
# Use system openssl.
OPENSSL_NO_VENDOR = 1;
nativeBuildInputs = [ pkg-config ];
buildInputs = [ openssl ];
preBuild = ''
export OPENSSL_DIR=${lib.getDev openssl}
export OPENSSL_LIB_DIR=${lib.getLib openssl}/lib
export SQLITE_MAX_VARIABLE_NUMBER=250000
export SQLITE_MAX_EXPR_DEPTH=10000
export GIT_HASH=0000000000000000000000000000000000000000
'';
cargoBuildFlags = [
"-p"
"schema-engine-cli"
];
# Tests are long to compile
doCheck = false;
setupHook = ./setup-hook.sh;
meta = with lib; {
description = "Collection of engines that power the core stack for Prisma";
homepage = "https://www.prisma.io/";
license = licenses.asl20;
platforms = platforms.unix;
mainProgram = "prisma";
maintainers = with maintainers; [
aqrln
];
};
}
### Troubleshooting
# Here's an example application using Prisma with Nix: https://github.com/pimeys/nix-prisma-example
# At example's `flake.nix` shellHook, notice the requirement of defining environment variables for prisma, it's values will show on `prisma --version`.
# Read the example's README: https://github.com/pimeys/nix-prisma-example/blob/main/README.md
# Prisma requires 2 packages, `prisma-engines` and `prisma`, to be at *exact* same versions.
# Certify at `package.json` that dependencies "@prisma/client" and "prisma" are equal, meaning no caret (`^`) in version.
# Configure NPM to use exact version: `npm config set save-exact=true`
# Delete `package-lock.json`, delete `node_modules` directory and run `npm install`.
# Run prisma client from `node_modules/.bin/prisma`.
# Run `./node_modules/.bin/prisma --version` and check if both prisma packages versions are equal, current platform is `linux-nixos`, and other keys equal to the prisma environment variables you defined for prisma.
# Test prisma with `generate`, `db push`, etc. It should work. If not, open an issue.
@@ -0,0 +1 @@
export PRISMA_SCHEMA_ENGINE_BINARY="@out@/bin/schema-engine"
@@ -6,21 +6,21 @@
pnpm_10,
fetchPnpmDeps,
pnpmConfigHook,
prisma-engines,
prisma-engines_6,
jq,
makeWrapper,
moreutils,
callPackage,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "prisma";
version = "6.19.0";
pname = "prisma_6";
version = "6.19.1";
src = fetchFromGitHub {
owner = "prisma";
repo = "prisma";
rev = finalAttrs.version;
hash = "sha256-lFPAu296cQMDnEcLTReSHuLuOz13kd7n0GV+ifcX+lQ=";
tag = finalAttrs.version;
hash = "sha256-73cnyg3NnQi2TLcGGhNYs95DRiVPz1LYStNsRw2EBNE=";
};
nativeBuildInputs = [
@@ -36,7 +36,7 @@ stdenv.mkDerivation (finalAttrs: {
inherit (finalAttrs) pname version src;
pnpm = pnpm_10;
fetcherVersion = 1;
hash = "sha256-9v30vhclD+sPcui/VG8dwaC8XGU6QFs/Gu8rjjoQy/w=";
hash = "sha256-y0gxeOeQNZZu3/UEI/DmdhVD8kSrUnK5G/n/WLhiLZ4=";
};
patchPhase = ''
@@ -86,9 +86,9 @@ stdenv.mkDerivation (finalAttrs: {
makeWrapper "${lib.getExe nodejs}" "$out/bin/prisma" \
--add-flags "$out/lib/prisma/packages/cli/build/index.js" \
--set PRISMA_SCHEMA_ENGINE_BINARY ${prisma-engines}/bin/schema-engine \
--set PRISMA_QUERY_ENGINE_BINARY ${prisma-engines}/bin/query-engine \
--set PRISMA_QUERY_ENGINE_LIBRARY ${lib.getLib prisma-engines}/lib/libquery_engine.node
--set PRISMA_SCHEMA_ENGINE_BINARY ${prisma-engines_6}/bin/schema-engine \
--set PRISMA_QUERY_ENGINE_BINARY ${prisma-engines_6}/bin/query-engine \
--set PRISMA_QUERY_ENGINE_LIBRARY ${lib.getLib prisma-engines_6}/lib/libquery_engine.node
runHook postInstall
'';
@@ -1,20 +1,22 @@
{
lib,
runCommand,
prisma,
prisma-engines,
prisma_6,
prisma-engines_6,
sqlite-interactive,
openssl,
}:
let
prismaMajorVersion = lib.versions.majorMinor prisma.version;
enginesMajorVersion = lib.versions.majorMinor prisma-engines.version;
prismaMajorVersion = lib.versions.majorMinor prisma_6.version;
enginesMajorVersion = lib.versions.majorMinor prisma-engines_6.version;
in
runCommand "prisma-cli-tests"
{
nativeBuildInputs = [
prisma
prisma_6
sqlite-interactive
openssl
];
meta.timeout = 60;
}
@@ -30,8 +32,9 @@ runCommand "prisma-cli-tests"
# Ensure CLI runs
prisma --help > /dev/null
# Init a new project
prisma init > /dev/null
# Init a new project without prisma init, which needs
# network access
mkdir prisma
# Create a simple data model
cat << EOF > prisma/schema.prisma
+109
View File
@@ -0,0 +1,109 @@
{
lib,
fetchFromGitHub,
stdenv,
nodejs,
pnpm_10,
prisma-engines_7,
jq,
makeWrapper,
moreutils,
callPackage,
pnpmConfigHook,
fetchPnpmDeps,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "prisma_7";
version = "7.0.1";
src = fetchFromGitHub {
owner = "prisma";
repo = "prisma";
tag = finalAttrs.version;
hash = "sha256-bmmthEFMBMJAracWUCU/6Nyic05JglP5t1VAWPVKFnU=";
};
nativeBuildInputs = [
nodejs
pnpmConfigHook
jq
makeWrapper
moreutils
pnpm_10
];
pnpmDeps = fetchPnpmDeps {
inherit (finalAttrs) pname version src;
pnpm = pnpm_10;
fetcherVersion = 1;
hash = "sha256-sJmlMF8nay4/3LTHEWzBWaS8Xq91JRZlzKBfeMnJEMM=";
};
patchPhase = ''
runHook prePatch
for package in packages/*; do
jq --arg version $version '.version = $version' $package/package.json | sponge $package/package.json
done
runHook postPatch
'';
buildPhase = ''
runHook preBuild
pnpm build
runHook postBuild
'';
# FIXME: Use pnpm deploy: https://github.com/pnpm/pnpm/issues/5315
installPhase = ''
runHook preInstall
mkdir -p $out/lib/prisma
# Fetch CLI workspace dependencies
deps_json=$(pnpm list --filter ./packages/cli --prod --depth Infinity --json)
deps=$(jq -r '[.. | strings | select(startswith("link:../")) | sub("^link:../"; "")] | unique[]' <<< "$deps_json")
# Remove unnecessary external dependencies
find . -name node_modules -type d -prune -exec rm -rf {} +
pnpm install --offline --ignore-scripts --frozen-lockfile --prod
cp -r node_modules $out/lib/prisma
# Only install cli and its workspace dependencies
for package in cli $deps; do
filename=$(npm pack --json ./packages/$package | jq -r '.[].filename')
mkdir -p $out/lib/prisma/packages/$package
[ -d "packages/$package/node_modules" ] && \
cp -r packages/$package/node_modules $out/lib/prisma/packages/$package
tar xf $filename --strip-components=1 -C $out/lib/prisma/packages/$package
done
# Remove dangling symlinks to packages we didn't copy to $out
find $out/lib/prisma/node_modules/.pnpm/node_modules -type l -exec test ! -e {} \; -delete
makeWrapper "${lib.getExe nodejs}" "$out/bin/prisma" \
--add-flags "$out/lib/prisma/packages/cli/build/index.js" \
--set PRISMA_SCHEMA_ENGINE_BINARY ${prisma-engines_7}/bin/schema-engine
runHook postInstall
'';
dontStrip = true;
passthru.tests = {
cli = callPackage ./test-cli.nix { };
};
meta = with lib; {
description = "Next-generation ORM for Node.js and TypeScript";
homepage = "https://www.prisma.io/";
license = licenses.asl20;
maintainers = with maintainers; [ aqrln ];
mainProgram = "prisma";
platforms = platforms.unix;
};
})
+83
View File
@@ -0,0 +1,83 @@
{
lib,
runCommand,
prisma_7,
prisma-engines_7,
sqlite-interactive,
openssl,
}:
let
prismaMajorVersion = lib.versions.majorMinor prisma_7.version;
enginesMajorVersion = lib.versions.majorMinor prisma-engines_7.version;
in
runCommand "prisma-cli-tests"
{
nativeBuildInputs = [
prisma_7
sqlite-interactive
openssl
];
meta.timeout = 60;
}
''
mkdir $out
cd $out
# Set HOME to a writable directory (Nix sandbox sets it to /homeless-shelter)
export HOME=$TMPDIR
if [ "${prismaMajorVersion}" != "${enginesMajorVersion}" ]; then
echo "prisma in version ${prismaMajorVersion} and prisma-engines in ${enginesMajorVersion}. Major versions must match."
exit 1
fi
# Ensure CLI runs
prisma --help > /dev/null
# Create project structure manually (prisma init requires network access)
mkdir -p prisma node_modules
# The config file needs to be able to import from 'prisma/config'
# so we symlink the prisma package into node_modules
ln -s ${prisma_7}/lib/prisma/packages/cli node_modules/prisma
cat << 'EOF' > prisma.config.ts
import { defineConfig } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: 'file:prisma/test.db',
},
})
EOF
# Create a simple data model
cat << 'EOF' > prisma/schema.prisma
datasource db {
provider = "sqlite"
}
generator client {
provider = "prisma-client"
}
model A {
id Int @id @default(autoincrement())
b String @default("foo")
}
EOF
# Format
prisma format > /dev/null
# Create the database
prisma db push > /dev/null
# The database file should exist and be a SQLite database
sqlite3 prisma/test.db "SELECT id, b FROM A" > /dev/null
# Introspect the database
prisma db pull > /dev/null
''
+3 -3
View File
@@ -9,16 +9,16 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "qrtool";
version = "0.13.1";
version = "0.13.2";
src = fetchFromGitHub {
owner = "sorairolake";
repo = "qrtool";
tag = "v${finalAttrs.version}";
hash = "sha256-ckdtmnUupnKAaspLm/l+nmPNdQ/sFAusQehzWikxq7A=";
hash = "sha256-N/kxis/nLwl+cfmlIC0TzZe0nApp160VXWoWeDtOctU=";
};
cargoHash = "sha256-RGEHsMay7+sjmrKz4g6uFXt6fUFiu0xIjr4fQaARKIM=";
cargoHash = "sha256-PgtVl55gpVsDg3VMuqtQaR7hD2ebL5+ffLNdpHggxfg=";
nativeBuildInputs = [
asciidoctor
+3 -3
View File
@@ -12,19 +12,19 @@
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "raycast";
version = "1.103.7";
version = "1.104.1";
src =
{
aarch64-darwin = fetchurl {
name = "Raycast.dmg";
url = "https://releases.raycast.com/releases/${finalAttrs.version}/download?build=arm";
hash = "sha256-wsFjjBYF8yQE7y/WyTPX2OM5euqYK2PBcxbUFLB3XY0=";
hash = "sha256-zm+r7f7uTUPtvLTVyVf18VwADltyOur8lPqqvpWrRu8=";
};
x86_64-darwin = fetchurl {
name = "Raycast.dmg";
url = "https://releases.raycast.com/releases/${finalAttrs.version}/download?build=x86_64";
hash = "sha256-+btAHctDvsOLUG/v7c3PGxJTWAxj28laQu72Wq2pl/M=";
hash = "sha256-TQNWPQzrPw43heW+zOCei6rM5sQYcIz6MEXonj8F3WM=";
};
}
.${stdenvNoCC.system} or (throw "raycast: ${stdenvNoCC.system} is unsupported.");
+3 -3
View File
@@ -7,14 +7,14 @@
python3.pkgs.buildPythonApplication {
pname = "renode-dts2repl";
version = "0-unstable-2025-11-26";
version = "0-unstable-2025-12-18";
pyproject = true;
src = fetchFromGitHub {
owner = "antmicro";
repo = "dts2repl";
rev = "f0c3d27b0f190defce22eaba0cb3f0b410d5d3db";
hash = "sha256-Q90gF4UQqlRJ8Y116jp9gb/8hinpiTMg7QnXC7m2T+U=";
rev = "927f689d40c34fbe64f246abf9e6abf2d79f2fb5";
hash = "sha256-cR/rMXGOLNyQDJSg77AI8+sco446sQNI/4IuuWHLDhE=";
};
nativeBuildInputs = [
+2 -2
View File
@@ -12,11 +12,11 @@
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "shottr";
version = "1.9";
version = "1.9.1";
src = fetchurl {
url = "https://shottr.cc/dl/Shottr-${finalAttrs.version}.dmg";
hash = "sha256-Zk2VAjQGx/qH2IwUmgMC+4q0O7Sq3zx/epvJpER4BbA=";
hash = "sha256-C/15fbz+xSpeEitQBirWuVSEf+O1PWdsBaxDYfUM5bM=";
};
nativeBuildInputs = [ undmg ];
+2 -2
View File
@@ -7,14 +7,14 @@
python3Packages.buildPythonApplication rec {
pname = "smpmgr";
version = "0.15.0";
version = "0.16.0";
pyproject = true;
src = fetchFromGitHub {
owner = "intercreate";
repo = "smpmgr";
tag = version;
hash = "sha256-ZIIHxQLBwd5OAxFqg0iOrdC7Xu3oZPHSJjdpo2CidAg=";
hash = "sha256-woQ8NxHZ9lYKvEFjGbvBu7/949bzAV6hs9t/3+N7bJc=";
};
build-system = with python3Packages; [

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