From 3813bee20c621c78016a2c43bd014d85c7a7d6a6 Mon Sep 17 00:00:00 2001 From: t4ccer Date: Tue, 22 Oct 2024 19:43:00 -0600 Subject: [PATCH 1/4] pds: init at 0.4.74 --- pkgs/by-name/pd/pds/package.nix | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 pkgs/by-name/pd/pds/package.nix diff --git a/pkgs/by-name/pd/pds/package.nix b/pkgs/by-name/pd/pds/package.nix new file mode 100644 index 0000000000000..ad6b5371f5564 --- /dev/null +++ b/pkgs/by-name/pd/pds/package.nix @@ -0,0 +1,92 @@ +{ + stdenv, + makeBinaryWrapper, + removeReferencesTo, + srcOnly, + python3, + pnpm, + fetchFromGitHub, + nodejs, + vips, + pkg-config, + lib, +}: + +let + nodeSources = srcOnly nodejs; + pythonEnv = python3.withPackages (p: [ p.setuptools ]); +in + +stdenv.mkDerivation (finalAttrs: { + pname = "pds"; + version = "0.4.74"; + + src = fetchFromGitHub { + owner = "bluesky-social"; + repo = "pds"; + rev = "v${finalAttrs.version}"; + hash = "sha256-kNHsQ6funmo8bnkFBNWHQ0Fmd5nf/uh+x9buaRJMZnM="; + }; + + sourceRoot = "${finalAttrs.src.name}/service"; + + nativeBuildInputs = [ + makeBinaryWrapper + nodejs + pythonEnv + pkg-config + pnpm.configHook + removeReferencesTo + ]; + + # Required for `sharp` NPM dependency + buildInputs = [ vips ]; + + pnpmDeps = pnpm.fetchDeps { + inherit (finalAttrs) + pname + version + src + sourceRoot + ; + hash = "sha256-oU4dwlBdsMmgAUv1ICaOqaqucmg/TjKOZxjnxpm0qL8="; + }; + + buildPhase = '' + runHook preBuild + + pushd ./node_modules/.pnpm/better-sqlite3@*/node_modules/better-sqlite3 + npm run build-release --offline --nodedir="${nodeSources}" + find build -type f -exec remove-references-to -t "${nodeSources}" {} \; + popd + + makeWrapper "${lib.getExe nodejs}" "$out/bin/pds" \ + --add-flags --enable-source-maps \ + --add-flags "$out/lib/pds/index.js" \ + --set-default NODE_ENV production + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/{bin,lib/pds} + mv node_modules $out/lib/pds + mv index.js $out/lib/pds + + runHook postInstall + ''; + + meta = { + description = "Bluesky Personal Data Server (PDS)"; + homepage = "https://github.com/bluesky-social/pds"; + license = with lib.licenses; [ + mit + asl20 + ]; + maintainers = with lib.maintainers; [ t4ccer ]; + platforms = lib.platforms.unix; + mainProgram = "pds"; + }; +}) From dec23730b6f01da8f53c0817edc2da9a176983c7 Mon Sep 17 00:00:00 2001 From: t4ccer Date: Thu, 7 Nov 2024 21:35:39 -0700 Subject: [PATCH 2/4] pdsadmin: init at 0.4.74 --- pkgs/by-name/pd/pdsadmin/package.nix | 58 +++++++++++++++++++ .../pd/pdsadmin/pdsadmin-offline.patch | 24 ++++++++ 2 files changed, 82 insertions(+) create mode 100644 pkgs/by-name/pd/pdsadmin/package.nix create mode 100644 pkgs/by-name/pd/pdsadmin/pdsadmin-offline.patch diff --git a/pkgs/by-name/pd/pdsadmin/package.nix b/pkgs/by-name/pd/pdsadmin/package.nix new file mode 100644 index 0000000000000..60a045fdc5feb --- /dev/null +++ b/pkgs/by-name/pd/pdsadmin/package.nix @@ -0,0 +1,58 @@ +{ + stdenvNoCC, + fetchFromGitHub, + bash, + pds, + makeBinaryWrapper, + jq, + curl, + openssl, + lib, +}: + +stdenvNoCC.mkDerivation (finalAttrs: { + pname = "pdsadmin"; + inherit (pds) version src; + + patches = [ ./pdsadmin-offline.patch ]; + + nativeBuildInputs = [ makeBinaryWrapper ]; + + buildInputs = [ bash ]; + + strictDeps = true; + + buildPhase = '' + runHook preBuild + + substituteInPlace pdsadmin.sh \ + --replace-fail NIXPKGS_PDSADMIN_ROOT $out + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + install -Dm755 pdsadmin.sh $out/lib/pds/pdsadmin.sh + install -Dm755 pdsadmin/*.sh $out/lib/pds + makeWrapper "$out/lib/pds/pdsadmin.sh" "$out/bin/pdsadmin" \ + --prefix PATH : "${ + lib.makeBinPath [ + jq + curl + openssl + ] + }" + + runHook postInstall + ''; + + meta = { + description = "Admin scripts for Bluesky Personal Data Server (PDS)"; + inherit (pds.meta) homepage license; + maintainers = with lib.maintainers; [ t4ccer ]; + platforms = lib.platforms.unix; + mainProgram = "pdsadmin"; + }; +}) diff --git a/pkgs/by-name/pd/pdsadmin/pdsadmin-offline.patch b/pkgs/by-name/pd/pdsadmin/pdsadmin-offline.patch new file mode 100644 index 0000000000000..0b3fbee916c3e --- /dev/null +++ b/pkgs/by-name/pd/pdsadmin/pdsadmin-offline.patch @@ -0,0 +1,24 @@ +diff --git a/pdsadmin.sh b/pdsadmin.sh +index 913d2b4..b09c20c 100644 +--- a/pdsadmin.sh ++++ b/pdsadmin.sh +@@ -15,16 +15,11 @@ if [[ "${EUID}" -ne 0 ]]; then + exit 1 + fi + +-# Download the script, if it exists. +-SCRIPT_URL="${PDSADMIN_BASE_URL}/${COMMAND}.sh" +-SCRIPT_FILE="$(mktemp /tmp/pdsadmin.${COMMAND}.XXXXXX)" ++SCRIPT_FILE="NIXPKGS_PDSADMIN_ROOT/lib/pds/${COMMAND}.sh" + +-if ! curl --fail --silent --show-error --location --output "${SCRIPT_FILE}" "${SCRIPT_URL}"; then ++if ! [ -f "${SCRIPT_FILE}" ]; then + echo "ERROR: ${COMMAND} not found" + exit 2 + fi + +-chmod +x "${SCRIPT_FILE}" +-if "${SCRIPT_FILE}" "$@"; then +- rm --force "${SCRIPT_FILE}" +-fi ++"${SCRIPT_FILE}" "$@" From f0a46910005cbae9ce1429eddbac2c00022bf110 Mon Sep 17 00:00:00 2001 From: t4ccer Date: Tue, 22 Oct 2024 20:11:48 -0600 Subject: [PATCH 3/4] nixos/pds: init module --- .../manual/release-notes/rl-2505.section.md | 2 + nixos/modules/module-list.nix | 1 + nixos/modules/services/web-apps/pds.nix | 233 ++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 nixos/modules/services/web-apps/pds.nix diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 1fbd5aad9230f..4a4bdc0f88e8a 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -79,6 +79,8 @@ - [Actual Budget](https://actualbudget.org/), a local-first personal finance app. Available as [services.actual](#opt-services.actual.enable). +- [PDS](https://github.com/bluesky-social/pds), Personal Data Server for [bsky](https://bsky.social/). Available as [services.pds](option.html#opt-services.pds). + - [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable). - [nvidia-gpu](https://github.com/utkuozdemir/nvidia_gpu_exporter), a Prometheus exporter that scrapes `nvidia-smi` for GPU metrics. Available as [services.prometheus.exporters.nvidia-gpu](#opt-services.prometheus.exporters.nvidia-gpu.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 06979a4df508f..7de7d952d70fa 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1529,6 +1529,7 @@ ./services/web-apps/mobilizon.nix ./services/web-apps/openwebrx.nix ./services/web-apps/outline.nix + ./services/web-apps/pds.nix ./services/web-apps/peering-manager.nix ./services/web-apps/peertube.nix ./services/web-apps/pgpkeyserver-lite.nix diff --git a/nixos/modules/services/web-apps/pds.nix b/nixos/modules/services/web-apps/pds.nix new file mode 100644 index 0000000000000..b17cd628c1577 --- /dev/null +++ b/nixos/modules/services/web-apps/pds.nix @@ -0,0 +1,233 @@ +{ + lib, + pkgs, + config, + ... +}: +let + cfg = config.services.pds; + + inherit (lib) + getExe + mkEnableOption + mkIf + mkOption + mkPackageOption + escapeShellArgs + concatMapStringsSep + types + literalExpression + ; + + pdsadminWrapper = + let + cfgSystemd = config.systemd.services.pds.serviceConfig; + in + pkgs.writeShellScriptBin "pdsadmin" '' + DUMMY_PDS_ENV_FILE="$(mktemp)" + trap 'rm -f "$DUMMY_PDS_ENV_FILE"' EXIT + env "PDS_ENV_FILE=$DUMMY_PDS_ENV_FILE" \ + ${escapeShellArgs cfgSystemd.Environment} \ + ${concatMapStringsSep " " (envFile: "$(cat ${envFile})") cfgSystemd.EnvironmentFile} \ + ${getExe pkgs.pdsadmin} "$@" + ''; +in +# All defaults are from https://github.com/bluesky-social/pds/blob/8b9fc24cec5f30066b0d0b86d2b0ba3d66c2b532/installer.sh +{ + options.services.pds = { + enable = mkEnableOption "pds"; + + package = mkPackageOption pkgs "pds" { }; + + settings = mkOption { + type = types.submodule { + freeformType = types.attrsOf ( + types.oneOf [ + (types.nullOr types.str) + types.port + ] + ); + options = { + PDS_PORT = mkOption { + type = types.port; + default = 3000; + description = "Port to listen on"; + }; + + PDS_HOSTNAME = mkOption { + type = types.str; + example = "pds.example.com"; + description = "Instance hostname (base domain name)"; + }; + + PDS_BLOB_UPLOAD_LIMIT = mkOption { + type = types.str; + default = "52428800"; + description = "Size limit of uploaded blobs in bytes"; + }; + + PDS_DID_PLC_URL = mkOption { + type = types.str; + default = "https://plc.directory"; + description = "URL of DID PLC directory"; + }; + + PDS_BSKY_APP_VIEW_URL = mkOption { + type = types.str; + default = "https://api.bsky.app"; + description = "URL of bsky frontend"; + }; + + PDS_BSKY_APP_VIEW_DID = mkOption { + type = types.str; + default = "did:web:api.bsky.app"; + description = "DID of bsky frontend"; + }; + + PDS_REPORT_SERVICE_URL = mkOption { + type = types.str; + default = "https://mod.bsky.app"; + description = "URL of mod service"; + }; + + PDS_REPORT_SERVICE_DID = mkOption { + type = types.str; + default = "did:plc:ar7c4by46qjdydhdevvrndac"; + description = "DID of mod service"; + }; + + PDS_CRAWLERS = mkOption { + type = types.str; + default = "https://bsky.network"; + description = "URL of crawlers"; + }; + + PDS_DATA_DIRECTORY = mkOption { + type = types.str; + default = "/var/lib/pds"; + description = "Directory to store state"; + }; + + PDS_BLOBSTORE_DISK_LOCATION = mkOption { + type = types.nullOr types.str; + default = "/var/lib/pds/blocks"; + description = "Store blobs at this location, set to null to use e.g. S3"; + }; + + LOG_ENABLED = mkOption { + type = types.nullOr types.str; + default = "true"; + description = "Enable logging"; + }; + }; + }; + + description = '' + Environment variables to set for the service. Secrets should be + specified using {option}`environmentFile`. + + Refer to for available environment variables. + ''; + }; + + 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 `PDS_JWT_SECRET`, `PDS_ADMIN_PASSWORD`, + and `PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX` secrets. + `PDS_JWT_SECRET` and `PDS_ADMIN_PASSWORD` can be generated with + ``` + openssl rand --hex 16 + ``` + `PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX` can be generated with + ``` + openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32 + ``` + ''; + }; + + pdsadmin = { + enable = mkOption { + type = types.bool; + default = cfg.enable; + defaultText = literalExpression "config.services.pds.enable"; + description = "Add pdsadmin script to PATH"; + }; + }; + }; + + config = mkIf cfg.enable { + environment = mkIf cfg.pdsadmin.enable { + systemPackages = [ pdsadminWrapper ]; + }; + + systemd.services.pds = { + description = "pds"; + + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + ExecStart = getExe cfg.package; + Environment = lib.mapAttrsToList (k: v: "${k}=${if builtins.isInt v then toString v else v}") ( + lib.filterAttrs (_: v: v != null) cfg.settings + ); + + EnvironmentFile = cfg.environmentFiles; + User = "pds"; + Group = "pds"; + StateDirectory = "pds"; + StateDirectoryMode = "0755"; + Restart = "always"; + + # Hardening + RemoveIPC = true; + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; + NoNewPrivileges = true; + PrivateDevices = true; + ProtectClock = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + ProtectKernelModules = true; + PrivateMounts = true; + SystemCallArchitectures = [ "native" ]; + MemoryDenyWriteExecute = false; # required by V8 JIT + RestrictNamespaces = true; + RestrictSUIDSGID = true; + ProtectHostname = true; + LockPersonality = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = [ + "AF_UNIX" + "AF_INET" + "AF_INET6" + ]; + RestrictRealtime = true; + DeviceAllow = [ "" ]; + ProtectSystem = "strict"; + ProtectProc = "invisible"; + ProcSubset = "pid"; + ProtectHome = true; + PrivateUsers = true; + PrivateTmp = true; + UMask = "0077"; + }; + }; + + users = { + users.pds = { + group = "pds"; + isSystemUser = true; + }; + groups.pds = { }; + }; + + }; + + meta.maintainers = with lib.maintainers; [ t4ccer ]; +} From 9e2f53f2749a84c1ec08889fb99c313feb7e68a7 Mon Sep 17 00:00:00 2001 From: t4ccer Date: Sat, 9 Nov 2024 20:46:47 -0700 Subject: [PATCH 4/4] pds: add NixOS test --- nixos/tests/all-tests.nix | 1 + nixos/tests/pds.nix | 29 +++++++++++++++++++++++++++++ pkgs/by-name/pd/pds/package.nix | 5 +++++ 3 files changed, 35 insertions(+) create mode 100644 nixos/tests/pds.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 613ff1314488a..bf986ae81ef50 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -799,6 +799,7 @@ in { parsedmarc = handleTest ./parsedmarc {}; password-option-override-ordering = handleTest ./password-option-override-ordering.nix {}; pdns-recursor = handleTest ./pdns-recursor.nix {}; + pds = handleTest ./pds.nix {}; peerflix = handleTest ./peerflix.nix {}; peering-manager = handleTest ./web-apps/peering-manager.nix {}; peertube = handleTestOn ["x86_64-linux"] ./web-apps/peertube.nix {}; diff --git a/nixos/tests/pds.nix b/nixos/tests/pds.nix new file mode 100644 index 0000000000000..4c4ab2a64326d --- /dev/null +++ b/nixos/tests/pds.nix @@ -0,0 +1,29 @@ +import ./make-test-python.nix ( + { lib, ... }: + { + name = "PDS"; + + nodes.machine = { + services.pds = { + enable = true; + settings = { + PDS_PORT = 3000; + PDS_HOSTNAME = "example.com"; + + # Snake oil testing credentials + PDS_JWT_SECRET = "7b93fee53be046bf59c27a32a0fb2069"; + PDS_ADMIN_PASSWORD = "3a4077bc0d5f04eca945ef0509f7e809"; + PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX = "ae4f5028d04c833ba630f29debd5ff80b7700e43e9f4bf70f729a88cd6a6ce35"; + }; + }; + }; + + testScript = '' + machine.wait_for_unit("pds.service") + machine.wait_for_open_port(3000) + machine.succeed("curl --fail http://localhost:3000") + ''; + + meta.maintainers = with lib.maintainers; [ t4ccer ]; + } +) diff --git a/pkgs/by-name/pd/pds/package.nix b/pkgs/by-name/pd/pds/package.nix index ad6b5371f5564..8dfca8215acd7 100644 --- a/pkgs/by-name/pd/pds/package.nix +++ b/pkgs/by-name/pd/pds/package.nix @@ -9,6 +9,7 @@ nodejs, vips, pkg-config, + nixosTests, lib, }: @@ -78,6 +79,10 @@ stdenv.mkDerivation (finalAttrs: { runHook postInstall ''; + passthru.tests = { + inherit (nixosTests) pds; + }; + meta = { description = "Bluesky Personal Data Server (PDS)"; homepage = "https://github.com/bluesky-social/pds";