From 4193ef0ccde98f1c6e36fb57b2c902c312e71554 Mon Sep 17 00:00:00 2001 From: Defelo Date: Tue, 10 Mar 2026 16:41:53 +0100 Subject: [PATCH 1/4] olivetin: inline `gen` and `webui` into main derivation --- pkgs/by-name/ol/olivetin/package.nix | 241 +++++++++++++-------------- 1 file changed, 117 insertions(+), 124 deletions(-) diff --git a/pkgs/by-name/ol/olivetin/package.nix b/pkgs/by-name/ol/olivetin/package.nix index 90b5bb036013..7a1abd1bfd5e 100644 --- a/pkgs/by-name/ol/olivetin/package.nix +++ b/pkgs/by-name/ol/olivetin/package.nix @@ -14,145 +14,138 @@ nixosTests, }: -buildGoModule ( - finalAttrs: +buildGoModule (finalAttrs: { + pname = "olivetin"; + version = "2025.11.25"; - let - gen = stdenvNoCC.mkDerivation { - pname = "olivetin-gen"; - inherit (finalAttrs) version src; + src = fetchFromGitHub { + owner = "OliveTin"; + repo = "OliveTin"; + tag = finalAttrs.version; + hash = "sha256-HQLInEVXowWpDaSW/4bduUMdYsvQ0Rju1Rl2l9jupYA="; + }; - nativeBuildInputs = [ - writableTmpDirAsHomeHook - buf - protoc-gen-go - protoc-gen-go-grpc - grpc-gateway - ]; + patches = [ ./update-go-sum.patch ]; - buildPhase = '' - runHook preBuild + modRoot = "service"; - pushd proto - buf generate - popd + vendorHash = "sha256-xSroaS6fwHrQ0s09uD3bkBZWWxbIndiOGL2JPvKzC6E="; - runHook postBuild - ''; + ldflags = [ + "-s" + "-w" + "-X main.version=${finalAttrs.version}" + ]; - installPhase = '' - runHook preInstall + __darwinAllowLocalNetworking = true; - cp -r service/gen $out + gen = stdenvNoCC.mkDerivation { + pname = "olivetin-gen"; + inherit (finalAttrs) version src; - runHook postInstall - ''; - - postFixup = '' - find $out -type f -name '*.go' -exec \ - sed -i -E 's|//.*protoc-gen-go(-grpc)? +v.*$||' {} + - ''; - - outputHashMode = "recursive"; - outputHash = "sha256-wHqXsSV18mF/CfLQ0S4rGtT3QRcLnneYXAa8nXZaHpQ="; - }; - - webui = buildNpmPackage { - pname = "olivetin-webui"; - inherit (finalAttrs) version src; - - npmDepsHash = "sha256-a1BBNlGusdMlmDXgclGqkO8AywSd4DTQKkuBVzuzAfE="; - - sourceRoot = "${finalAttrs.src.name}/webui.dev"; - - buildPhase = '' - runHook preBuild - - npx parcel build --public-url "." - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - cp -r dist $out - cp -r *.png $out - - runHook postInstall - ''; - }; - in - - { - pname = "olivetin"; - version = "2025.11.25"; - - src = fetchFromGitHub { - owner = "OliveTin"; - repo = "OliveTin"; - tag = finalAttrs.version; - hash = "sha256-HQLInEVXowWpDaSW/4bduUMdYsvQ0Rju1Rl2l9jupYA="; - }; - - patches = [ ./update-go-sum.patch ]; - - modRoot = "service"; - - vendorHash = "sha256-xSroaS6fwHrQ0s09uD3bkBZWWxbIndiOGL2JPvKzC6E="; - - ldflags = [ - "-s" - "-w" - "-X main.version=${finalAttrs.version}" + nativeBuildInputs = [ + writableTmpDirAsHomeHook + buf + protoc-gen-go + protoc-gen-go-grpc + grpc-gateway ]; - __darwinAllowLocalNetworking = true; + buildPhase = '' + runHook preBuild - nativeBuildInputs = [ installShellFiles ]; + pushd proto + buf generate + popd - preBuild = '' - ln -s ${gen} gen - substituteInPlace internal/config/config.go \ - --replace-fail 'config.WebUIDir = "./webui"' 'config.WebUIDir = "${webui}"' - substituteInPlace internal/httpservers/webuiServer_test.go \ - --replace-fail '"../webui/"' '"${webui}"' + runHook postBuild ''; - postInstall = '' - installManPage ../var/manpage/OliveTin.1.gz + installPhase = '' + runHook preInstall + + cp -r service/gen $out + + runHook postInstall ''; - nativeInstallCheckInputs = [ versionCheckHook ]; - versionCheckProgram = "${placeholder "out"}/bin/OliveTin"; - versionCheckProgramArg = "-version"; - doInstallCheck = true; + postFixup = '' + find $out -type f -name '*.go' -exec \ + sed -i -E 's|//.*protoc-gen-go(-grpc)? +v.*$||' {} + + ''; - passthru = { - inherit gen webui; - tests = { inherit (nixosTests) olivetin; }; - updateScript = ./update.sh; - }; + outputHashMode = "recursive"; + outputHash = "sha256-wHqXsSV18mF/CfLQ0S4rGtT3QRcLnneYXAa8nXZaHpQ="; + }; - meta = { - description = "Gives safe and simple access to predefined shell commands from a web interface"; - homepage = "https://www.olivetin.app/"; - downloadPage = "https://github.com/OliveTin/OliveTin"; - changelog = "https://github.com/OliveTin/OliveTin/releases/tag/${finalAttrs.version}"; - license = lib.licenses.agpl3Only; - maintainers = with lib.maintainers; [ defelo ]; - mainProgram = "OliveTin"; - knownVulnerabilities = [ - "CVE-2026-27626: OS Command Injection via password argument type and webhook JSON extraction bypasses shell safety checks" - "CVE-2026-28342: Unauthenticated Denial of Service via Memory Exhaustion in PasswordHash API Endpoint" - "CVE-2026-28789: Unauthenticated DoS via concurrent map writes in OAuth2 state handling" - "CVE-2026-28790: Unauthenticated Action Termination via KillAction When Guests Must Login" - "CVE-2026-30223: JWT Audience Validation Bypass in Local Key and HMAC Modes" - "CVE-2026-30224: Session Fixation - Logout Fails to Invalidate Server-Side Session" - "CVE-2026-30225: RestartAction always runs actions as guest" - "CVE-2026-30233: View permission not being checked when returning dashboards" - "CVE-2026-31817: Unsafe parsing of UniqueTrackingId can be used to write files" - ]; - }; - } -) + webui = buildNpmPackage { + pname = "olivetin-webui"; + inherit (finalAttrs) version src; + + npmDepsHash = "sha256-a1BBNlGusdMlmDXgclGqkO8AywSd4DTQKkuBVzuzAfE="; + + sourceRoot = "${finalAttrs.src.name}/webui.dev"; + + buildPhase = '' + runHook preBuild + + npx parcel build --public-url "." + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + cp -r dist $out + cp -r *.png $out + + runHook postInstall + ''; + }; + + nativeBuildInputs = [ installShellFiles ]; + + preBuild = '' + ln -s ${finalAttrs.gen} gen + substituteInPlace internal/config/config.go \ + --replace-fail 'config.WebUIDir = "./webui"' 'config.WebUIDir = "${finalAttrs.webui}"' + substituteInPlace internal/httpservers/webuiServer_test.go \ + --replace-fail '"../webui/"' '"${finalAttrs.webui}"' + ''; + + postInstall = '' + installManPage ../var/manpage/OliveTin.1.gz + ''; + + nativeInstallCheckInputs = [ versionCheckHook ]; + versionCheckProgram = "${placeholder "out"}/bin/OliveTin"; + versionCheckProgramArg = "-version"; + doInstallCheck = true; + + passthru = { + tests = { inherit (nixosTests) olivetin; }; + updateScript = ./update.sh; + }; + + meta = { + description = "Gives safe and simple access to predefined shell commands from a web interface"; + homepage = "https://www.olivetin.app/"; + downloadPage = "https://github.com/OliveTin/OliveTin"; + changelog = "https://github.com/OliveTin/OliveTin/releases/tag/${finalAttrs.version}"; + license = lib.licenses.agpl3Only; + maintainers = with lib.maintainers; [ defelo ]; + mainProgram = "OliveTin"; + knownVulnerabilities = [ + "CVE-2026-27626: OS Command Injection via password argument type and webhook JSON extraction bypasses shell safety checks" + "CVE-2026-28342: Unauthenticated Denial of Service via Memory Exhaustion in PasswordHash API Endpoint" + "CVE-2026-28789: Unauthenticated DoS via concurrent map writes in OAuth2 state handling" + "CVE-2026-28790: Unauthenticated Action Termination via KillAction When Guests Must Login" + "CVE-2026-30223: JWT Audience Validation Bypass in Local Key and HMAC Modes" + "CVE-2026-30224: Session Fixation - Logout Fails to Invalidate Server-Side Session" + "CVE-2026-30225: RestartAction always runs actions as guest" + "CVE-2026-30233: View permission not being checked when returning dashboards" + "CVE-2026-31817: Unsafe parsing of UniqueTrackingId can be used to write files" + ]; + }; +}) From f12322ff1d3cb2b92f8192b29beb203410ba4526 Mon Sep 17 00:00:00 2001 From: Defelo Date: Tue, 10 Mar 2026 16:44:35 +0100 Subject: [PATCH 2/4] olivetin: remove explicit `versionCheckProgram` --- pkgs/by-name/ol/olivetin/package.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/by-name/ol/olivetin/package.nix b/pkgs/by-name/ol/olivetin/package.nix index 7a1abd1bfd5e..cff5463b694a 100644 --- a/pkgs/by-name/ol/olivetin/package.nix +++ b/pkgs/by-name/ol/olivetin/package.nix @@ -119,7 +119,6 @@ buildGoModule (finalAttrs: { ''; nativeInstallCheckInputs = [ versionCheckHook ]; - versionCheckProgram = "${placeholder "out"}/bin/OliveTin"; versionCheckProgramArg = "-version"; doInstallCheck = true; From 28cac75a516606b4abf0eca71c48eb120fe381c2 Mon Sep 17 00:00:00 2001 From: Defelo Date: Tue, 10 Mar 2026 17:12:15 +0100 Subject: [PATCH 3/4] olivetin: update `gen` hash --- pkgs/by-name/ol/olivetin/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/ol/olivetin/package.nix b/pkgs/by-name/ol/olivetin/package.nix index cff5463b694a..2e023a12a912 100644 --- a/pkgs/by-name/ol/olivetin/package.nix +++ b/pkgs/by-name/ol/olivetin/package.nix @@ -75,7 +75,7 @@ buildGoModule (finalAttrs: { ''; outputHashMode = "recursive"; - outputHash = "sha256-wHqXsSV18mF/CfLQ0S4rGtT3QRcLnneYXAa8nXZaHpQ="; + outputHash = "sha256-fTsJE9ymtJ0TU2OhXLE+XfEOckFMG7IPi0IHHAmN84s="; }; webui = buildNpmPackage { From 059e991229cc8dd5f38553a5b9227bbba9b6194f Mon Sep 17 00:00:00 2001 From: Defelo Date: Tue, 10 Mar 2026 17:22:29 +0100 Subject: [PATCH 4/4] olivetin-3k: init at 3000.11.3 --- nixos/modules/services/web-apps/olivetin.nix | 12 +- nixos/tests/olivetin.nix | 16 ++- pkgs/by-name/ol/olivetin/3k.nix | 141 +++++++++++++++++++ pkgs/by-name/ol/olivetin/package.nix | 7 +- pkgs/by-name/ol/olivetin/update-3k.sh | 9 ++ pkgs/top-level/all-packages.nix | 2 + 6 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 pkgs/by-name/ol/olivetin/3k.nix create mode 100755 pkgs/by-name/ol/olivetin/update-3k.sh diff --git a/nixos/modules/services/web-apps/olivetin.nix b/nixos/modules/services/web-apps/olivetin.nix index 718c732e3c5a..2709fbb885ba 100644 --- a/nixos/modules/services/web-apps/olivetin.nix +++ b/nixos/modules/services/web-apps/olivetin.nix @@ -17,7 +17,17 @@ in options.services.olivetin = { enable = lib.mkEnableOption "OliveTin"; - package = lib.mkPackageOption pkgs "olivetin" { }; + package = lib.mkOption { + type = lib.types.package; + description = "The olivetin package to use."; + default = + if lib.versionAtLeast config.system.stateVersion "26.05" then pkgs.olivetin-3k else pkgs.olivetin; + defaultText = lib.literalExpression '' + if lib.versionAtLeast config.system.stateVersion "26.05" + then pkgs.olivetin-3k + else pkgs.olivetin + ''; + }; user = lib.mkOption { type = lib.types.str; diff --git a/nixos/tests/olivetin.nix b/nixos/tests/olivetin.nix index f9d9e98610ef..552ff24ff282 100644 --- a/nixos/tests/olivetin.nix +++ b/nixos/tests/olivetin.nix @@ -1,4 +1,4 @@ -{ lib, ... }: +{ config, lib, ... }: { name = "olivetin"; @@ -41,16 +41,26 @@ testScript = '' import json + import shlex machine.wait_for_unit("olivetin.service") machine.wait_for_open_port(8000) - response = json.loads(machine.succeed("curl http://localhost:8000/api/StartActionByGetAndWait/hello_world")) + def start_action(action): + if "${config.nodes.machine.services.olivetin.package.releaseSeries}" == "2k": + cmd = f"curl http://localhost:8000/api/StartActionByGetAndWait/{action}" + else: + req = {"actionId": action} + cmd = f"curl -H 'Content-Type: application/json' http://localhost:8000/api/olivetin.api.v1.OliveTinApiService/StartActionAndWait -d {shlex.quote(json.dumps(req))}" + + return json.loads(machine.succeed(cmd)) + + response = start_action("hello_world") assert response["logEntry"]["exitCode"] == 0 assert response["logEntry"]["output"] == "Hello World!" assert machine.succeed("cat /tmp/result") == "Hello World!" - response = json.loads(machine.succeed("curl http://localhost:8000/api/StartActionByGetAndWait/secret")) + response = start_action("secret") assert response["logEntry"]["exitCode"] == 0 assert machine.succeed("cat /tmp/result2") == "secret" ''; diff --git a/pkgs/by-name/ol/olivetin/3k.nix b/pkgs/by-name/ol/olivetin/3k.nix new file mode 100644 index 000000000000..fe8023a74651 --- /dev/null +++ b/pkgs/by-name/ol/olivetin/3k.nix @@ -0,0 +1,141 @@ +{ + lib, + fetchFromGitHub, + buildGoModule, + stdenvNoCC, + writableTmpDirAsHomeHook, + buf, + protoc-gen-go, + protoc-gen-go-grpc, + grpc-gateway, + buildNpmPackage, + installShellFiles, + versionCheckHook, + nixosTests, +}: + +buildGoModule (finalAttrs: { + pname = "olivetin"; + version = "3000.11.3"; + + src = fetchFromGitHub { + owner = "OliveTin"; + repo = "OliveTin"; + tag = finalAttrs.version; + hash = "sha256-GSCqtekFj0c2TPSygRiUAfSMQAyPbfuR0dxAGQ/Rghw="; + }; + + modRoot = "service"; + + vendorHash = "sha256-iH9tgw4KSER/xIPOIontSQLWrI4ORayRjyHsT1HU0m8="; + + subPackages = [ "." ]; + + ldflags = [ + "-s" + "-w" + "-X main.version=${finalAttrs.version}" + ]; + + __darwinAllowLocalNetworking = true; + + gen = stdenvNoCC.mkDerivation { + pname = "olivetin-gen"; + inherit (finalAttrs) version src; + + nativeBuildInputs = [ + writableTmpDirAsHomeHook + buf + protoc-gen-go + protoc-gen-go-grpc + grpc-gateway + ]; + + buildPhase = '' + runHook preBuild + + pushd proto + buf generate + popd + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + cp -r service/gen $out + + runHook postInstall + ''; + + postFixup = '' + find $out -type f -name '*.go' -exec \ + sed -i -E 's|//.*protoc-gen-go(-grpc)? +v.*$||' {} + + ''; + + outputHashMode = "recursive"; + outputHash = "sha256-SaGHxawFw55zI37psqI9kdaR8DLnx4iV2XZdomr28b8="; + }; + + webui = buildNpmPackage { + pname = "olivetin-webui"; + inherit (finalAttrs) version src; + + npmDepsHash = "sha256-vrvwy96wtXxt0JJDs8YG0Lm3kpVRoJ2Qmu8nlggH6qc="; + + sourceRoot = "${finalAttrs.src.name}/frontend"; + + buildPhase = '' + runHook preBuild + + make build + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + cp -r dist $out + + runHook postInstall + ''; + }; + + nativeBuildInputs = [ installShellFiles ]; + + preBuild = '' + ln -s ${finalAttrs.gen} gen + substituteInPlace internal/config/config.go \ + --replace-fail 'config.WebUIDir = "./webui"' 'config.WebUIDir = "${finalAttrs.webui}"' + ''; + + postInstall = '' + installManPage ../var/manpage/OliveTin.1.gz + ''; + + nativeInstallCheckInputs = [ versionCheckHook ]; + versionCheckProgramArg = "-version"; + doInstallCheck = true; + + passthru = { + tests.olivetin = nixosTests.olivetin.extendNixOS { + module = { + services.olivetin.package = finalAttrs.finalPackage; + }; + }; + releaseSeries = "3k"; + updateScript = ./update-3k.sh; + }; + + meta = { + description = "Gives safe and simple access to predefined shell commands from a web interface"; + homepage = "https://www.olivetin.app/"; + downloadPage = "https://github.com/OliveTin/OliveTin"; + changelog = "https://github.com/OliveTin/OliveTin/releases/tag/${finalAttrs.version}"; + license = lib.licenses.agpl3Only; + maintainers = with lib.maintainers; [ defelo ]; + mainProgram = "OliveTin"; + }; +}) diff --git a/pkgs/by-name/ol/olivetin/package.nix b/pkgs/by-name/ol/olivetin/package.nix index 2e023a12a912..219c7367d106 100644 --- a/pkgs/by-name/ol/olivetin/package.nix +++ b/pkgs/by-name/ol/olivetin/package.nix @@ -123,7 +123,12 @@ buildGoModule (finalAttrs: { doInstallCheck = true; passthru = { - tests = { inherit (nixosTests) olivetin; }; + tests.olivetin = nixosTests.olivetin.extendNixOS { + module = { + services.olivetin.package = finalAttrs.finalPackage; + }; + }; + releaseSeries = "2k"; updateScript = ./update.sh; }; diff --git a/pkgs/by-name/ol/olivetin/update-3k.sh b/pkgs/by-name/ol/olivetin/update-3k.sh new file mode 100755 index 000000000000..683d80cd9682 --- /dev/null +++ b/pkgs/by-name/ol/olivetin/update-3k.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash -p nix-update common-updater-scripts + +set -euo pipefail + +nix-update olivetin-3k --src-only --override-filename +update-source-version olivetin-3k --source-key=gen --ignore-same-version +update-source-version olivetin-3k --source-key=webui.npmDeps --ignore-same-version +update-source-version olivetin-3k --source-key=goModules --ignore-same-version diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index f75b9171cf53..290ed6f69c41 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -12437,6 +12437,8 @@ with pkgs; radicle-node-unstable = callPackage ../by-name/ra/radicle-node/unstable.nix { }; + olivetin-3k = callPackage ../by-name/ol/olivetin/3k.nix { }; + newlib-nano = newlib.override { nanoizeNewlib = true; };