tranquil-pds: init at 0.6.3, tranquil-pds-frontend: init at 0.6.3, nixos/tranquil-pds: init module; nixosTests.tranquil-pds: init (#525658)

This commit is contained in:
isabel
2026-05-30 13:19:51 +00:00
committed by GitHub
8 changed files with 402 additions and 1 deletions

View File

@@ -19399,6 +19399,11 @@
githubId = 79978224;
name = "winston";
};
nelind = {
name = "Nel";
github = "nelind3";
githubId = 57587152;
};
nelsonjeppesen = {
email = "nix@jeppesen.io";
github = "NelsonJeppesen";

View File

@@ -10,7 +10,7 @@
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
- Create the first release note entry in this section!
- [tranquil](https://tangled.org/tranquil.farm/tranquil-pds) is an ATProto PDS (personal data server) implementation in Rust. A featureful, spec conscious and community driven alternative to the Bluesky reference implementation PDS. Available as [services.tranquil-pds](#opt-services.tranquil-pds.enable).
## Backward Incompatibilities {#sec-release-26.11-incompatibilities}

View File

@@ -1793,6 +1793,7 @@
./services/web-apps/suwayomi-server.nix
./services/web-apps/szurubooru.nix
./services/web-apps/tabbyapi.nix
./services/web-apps/tranquil-pds.nix
./services/web-apps/trilium.nix
./services/web-apps/tt-rss.nix
./services/web-apps/tuliprox.nix

View File

@@ -0,0 +1,251 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.services.tranquil-pds;
inherit (lib) types mkPackageOption mkOption;
settingsFormat = pkgs.formats.toml { };
in
{
options.services.tranquil-pds = {
enable = lib.mkEnableOption "tranquil-pds AT Protocol personal data server";
package = mkPackageOption pkgs "tranquil-pds" { };
user = mkOption {
type = types.str;
default = "tranquil-pds";
description = "User under which tranquil-pds runs";
};
group = mkOption {
type = types.str;
default = "tranquil-pds";
description = "Group under which tranquil-pds runs";
};
dataDir = mkOption {
type = types.str;
default = "/var/lib/tranquil-pds";
description = "Working directory for tranquil-pds. Also expected to be used for data (blobs)";
};
environmentFiles = mkOption {
type = types.listOf types.path;
default = [ ];
description = ''
File to load environment variables from. Loaded variables override
values set in {option}`environment`.
Use it to set values of `JWT_SECRET`, `DPOP_SECRET` and `MASTER_KEY`.
Generate these with:
```
openssl rand -base64 48
```
'';
};
database.createLocally = mkOption {
type = types.bool;
default = false;
description = ''
Create the postgres database and user on the local host.
'';
};
settings = mkOption {
type = types.submodule {
freeformType = settingsFormat.type;
options = {
server = {
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Host for tranquil-pds to listen on";
};
port = mkOption {
type = types.int;
default = 3000;
description = "Port for tranquil-pds to listen on";
};
hostname = mkOption {
type = types.str;
default = "";
example = "pds.example.com";
description = "The public-facing hostname of the PDS";
};
max_blob_size = mkOption {
type = types.int;
default = 10737418240; # 10 GiB
description = "Maximum allowed blob size in bytes.";
};
};
frontend = {
enabled =
lib.mkEnableOption "serving the frontend from the backend. Disable to serve the frontend manually"
// {
default = true;
};
dir = mkPackageOption pkgs "tranquil-pds-frontend" { };
};
storage = {
path = mkOption {
type = types.path;
default = "${cfg.dataDir}/blobs";
defaultText = "\${cfg.dataDir}/blobs";
description = "Directory for storing blobs";
};
};
tranquil_store = {
data_dir = mkOption {
type = types.path;
default = "${cfg.dataDir}/store";
defaultText = "\${cfg.dataDir}/store";
description = "Directory for tranquil-store files";
};
};
};
};
description = ''
Configuration options to set for the service. Secrets should be
specified using {option}`environmentFile`.
Refer to <https://tangled.org/tranquil.farm/tranquil-pds/blob/main/example.toml>
for available configuration options.
'';
};
};
config = lib.mkIf cfg.enable (
lib.mkMerge [
(lib.mkIf cfg.database.createLocally {
services.postgresql = {
enable = true;
ensureDatabases = [ cfg.user ];
ensureUsers = [
{
name = cfg.user;
ensureDBOwnership = true;
}
];
};
services.tranquil-pds.settings.database.url =
lib.mkDefault "postgresql:///${cfg.user}?host=/run/postgresql";
systemd.services.tranquil-pds = {
requires = [ "postgresql.service" ];
after = [ "postgresql.service" ];
};
})
{
users.users.${cfg.user} = {
isSystemUser = true;
inherit (cfg) group;
home = cfg.dataDir;
};
users.groups.${cfg.group} = { };
systemd.tmpfiles.settings."tranquil-pds" =
lib.genAttrs
[
cfg.dataDir
cfg.settings.storage.path
cfg.settings.tranquil_store.data_dir
]
(_: {
d = {
mode = "0750";
inherit (cfg) user group;
};
});
environment.etc = {
"tranquil-pds/config.toml".source =
let
conf = settingsFormat.generate "tranquil-pds.toml" cfg.settings;
in
pkgs.runCommandLocal "validated-tranquil-config" { nativeBuildInputs = [ cfg.package ]; } ''
tranquil-server --config ${conf} validate --ignore-secrets
ln -s ${conf} $out
'';
};
systemd.services.tranquil-pds = {
description = "Tranquil PDS - ATProtocol Personal Data Server";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = cfg.user;
Group = cfg.group;
UMask = "0077";
ExecStart = lib.getExe cfg.package;
Restart = "on-failure";
RestartSec = 5;
WorkingDirectory = cfg.dataDir;
StateDirectory = "tranquil-pds";
ReadWritePaths = [
cfg.settings.storage.path
];
EnvironmentFile = cfg.environmentFiles;
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
ProtectProc = "invisible";
ProcSubset = "pid";
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RemoveIPC = true;
PrivateMounts = true;
SystemCallFilter = [
"@system-service"
"~@privileged @resources"
];
SystemCallArchitectures = "native";
};
};
}
]
);
meta.maintainers = with lib.maintainers; [ nelind ];
}

View File

@@ -1708,6 +1708,7 @@ in
tracee = handleTestOn [ "x86_64-linux" ] ./tracee.nix { };
traefik = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./traefik.nix;
trafficserver = runTest ./trafficserver.nix;
tranquil-pds = runTest ./tranquil-pds.nix;
transfer-sh = runTest ./transfer-sh.nix;
transmission_4 = runTest ./transmission.nix;
trezord = runTest ./trezord.nix;

View File

@@ -0,0 +1,35 @@
{ lib, ... }:
{
name = "tranquil-pds";
nodes.machine =
{ pkgs, ... }:
{
services.tranquil-pds = {
enable = true;
database.createLocally = true;
settings = {
server = {
hostname = "pds";
port = 8080;
};
secrets = {
allow_insecure = true;
jwt_secret = "test-jwt-secret-must-be-32-chars-long";
dpop_secret = "test-dpop-secret-must-be-32-chars-long";
master_key = "test-master-key-must-be-32-chars-long";
};
};
};
};
testScript = ''
machine.wait_for_unit("tranquil-pds.service")
machine.wait_for_open_port(8080)
machine.succeed("curl --fail http://localhost:8080")
'';
meta.maintainers = with lib.maintainers; [ nelind ];
}

View File

@@ -0,0 +1,61 @@
{
lib,
stdenvNoCC,
fetchgit,
nodejs,
pnpm,
pnpmConfigHook,
fetchPnpmDeps,
}:
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "tranquil-frontend";
version = "0.6.3";
src = fetchgit {
url = "https://tangled.org/tranquil.farm/tranquil-pds";
tag = "v${finalAttrs.version}";
hash = "sha256-TORNOFPlbCt4QWNd+bmxkShTUvT/5ynOj+UBYITAhg8=";
};
sourceRoot = "${finalAttrs.src.name}/frontend";
pnpmDeps = fetchPnpmDeps {
inherit (finalAttrs)
pname
version
src
sourceRoot
;
inherit pnpm;
fetcherVersion = 4;
hash = "sha256-qbmIAvE/3u/NB5x9bERCGQqwiDLkzjff3QchgR+ZDFs=";
};
strictDeps = true;
__structuredAttrs = true;
nativeBuildInputs = [
pnpm
nodejs
pnpmConfigHook
];
buildPhase = ''
runHook preBuild
pnpm build
runHook postBuild
'';
installPhase = ''
runHook preInstall
cp -r ./dist $out
runHook postInstall
'';
meta = {
description = "First party frontend for the Tranquil PDS implementation";
homepage = "https://tangled.org/tranquil.farm/tranquil-pds";
license = lib.licenses.agpl3Plus;
maintainers = with lib.maintainers; [ nelind ];
};
})

View File

@@ -0,0 +1,47 @@
{
lib,
fetchgit,
rustPlatform,
pkg-config,
openssl,
protobuf,
nixosTests,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "tranquil-pds";
version = "0.6.3";
src = fetchgit {
url = "https://tangled.org/tranquil.farm/tranquil-pds";
tag = "v${finalAttrs.version}";
hash = "sha256-TORNOFPlbCt4QWNd+bmxkShTUvT/5ynOj+UBYITAhg8=";
};
cargoHash = "sha256-tQk9WQZmaG2XEx5gocPhYd8fZ2cikvduhln5h/w+WZA=";
__structuredAttrs = true;
nativeBuildInputs = [
pkg-config
protobuf
];
buildInputs = [
openssl
];
# the tranquil test suite has shown itself virtually impossible to complete on most hardware thus stopping reviews.
# disable the check phase for now
doCheck = false;
passthru.tests = { inherit (nixosTests) tranquil-pds; };
meta = {
description = "Tranquil ATProto Personal Data Server implementation written in Rust";
homepage = "https://tangled.org/tranquil.farm/tranquil-pds";
license = lib.licenses.agpl3Plus;
maintainers = with lib.maintainers; [ nelind ];
mainProgram = "tranquil-server";
};
})