diff options
| author | Jakub Stachurski <j.stachurski@student.utwente.nl> | 2026-05-20 22:35:25 +0200 |
|---|---|---|
| committer | Jakub Stachurski <j.stachurski@student.utwente.nl> | 2026-05-20 22:35:25 +0200 |
| commit | 2e300b08ee2697656a76b4c95a4c66039510a239 (patch) | |
| tree | 36996b3ab8ae6161e0d466b6f5233f0066af0ac2 | |
| parent | 98080b79cfbac8f4a7c17af91e697ae84278f8ab (diff) | |
Self-Package stalwart
| -rw-r--r-- | flake.nix | 12 | ||||
| -rw-r--r-- | packages/stalwart-cli/package.nix | 52 | ||||
| -rw-r--r-- | packages/stalwart/package.nix | 211 | ||||
| -rw-r--r-- | packages/stalwart/spam-filter.nix | 42 | ||||
| -rw-r--r-- | packages/stalwart/webadmin.nix | 77 |
5 files changed, 390 insertions, 4 deletions
@@ -70,10 +70,14 @@ treefmtExtract = name: (builtins.mapAttrs (_system: conf: conf."${name}") (treefmtStuff)); in { - packages."x86_64-linux".full-iso = self.nixosConfigurations.full-iso.config.system.build.isoImage; - packages."x86_64-linux".bulwark = - nixpkgs.legacyPackages."x86_64-linux".callPackage ./packages/bulwark/package.nix - { }; + packages = let system = "x86_64-linux"; pkgs = import nixpkgs {inherit system;}; in { + ${system} = { + full-iso = self.nixosConfigurations.full-iso.config.system.build.isoImage; + bulwark = pkgs.callPackage ./packages/bulwark/package.nix {}; + stalwart = pkgs.callPackage ./packages/stalwart/package.nix {}; + stalwart-cli = pkgs.callPackage ./packages/stalwart-cli/package.nix {}; + }; + }; # for `nix fmt` formatter = treefmtExtract "formatter"; # for `nix flake check` diff --git a/packages/stalwart-cli/package.nix b/packages/stalwart-cli/package.nix new file mode 100644 index 0000000..6c89fa2 --- /dev/null +++ b/packages/stalwart-cli/package.nix @@ -0,0 +1,52 @@ +{ + lib, + rustPlatform, + versionCheckHook, + stalwart, + fetchFromGitHub, + openssl, + pkg-config, + nix-update-script, +}: +rustPlatform.buildRustPackage (finalAttrs: { + pname = "stalwart-cli"; + version = "1.0.7"; + src = fetchFromGitHub { + owner = "stalwartlabs"; + repo = "cli"; + tag = "v${finalAttrs.version}"; + hash = ""; + }; + + cargoHash = ""; + + nativeBuildInputs = [ pkg-config ]; + buildInputs = [ openssl ]; + + env.OPENSSL_NO_VENDOR = true; + + cargoBuildFlags = [ + "--package" + "stalwart-cli" + ]; + cargoTestFlags = [ + "--package" + "stalwart-cli" + ]; + + doInstallCheck = true; + nativeInstallCheckInputs = [ versionCheckHook ]; + + passthru.updateScript = nix-update-script { }; + + meta = { + description = "Stalwart Mail Server CLI"; + mainProgram = "stalwart-cli"; + homepage = "https://github.com/stalwartlabs/cli"; + changelog = "https://github.com/stalwartlabs/cli/blob/main/CHANGELOG.md"; + license = lib.licenses.agpl3Only; + # maintainers = with lib.maintainers; [ + # giomf + # ]; + }; +}) diff --git a/packages/stalwart/package.nix b/packages/stalwart/package.nix new file mode 100644 index 0000000..185fa5a --- /dev/null +++ b/packages/stalwart/package.nix @@ -0,0 +1,211 @@ +{ + lib, + rustPlatform, + fetchFromGithub, + pkg-config, + protobuf, + bzip2, + openssl, + sqlite, + foundationdb, + zstd, + stdenv, + nix-update-script, + nixosTest, + rocksdb, + callPackage, + withFoundationdb ? false, + stalwartEnterprise ? false, + buildPackages, +}: + rustPlatform.makeRustPackage (finalAttrs: { + pname = "stalwart" + (lib.optionalString stalwartEnterprise "-enterprise"); + version = "0.16.6"; + src = fetchFromGithub { + owner = "stalwartlabs"; + repo = "stalwart"; + tag = "v${finalAttrs.version}"; + hash = ""; + }; + + cargoHash = ""; + + depsBuildBuild = [ + pkg-config + zstd + ]; + + nativeBuildInputs = [ + protobuf + rustPlatform.bindgenHook + ]; + + buildInputs = [ + bzip2 + openssl + sqlite + zstd + ] ++ lib.optional (stdenv.hostPlatform.isLinux && withFoundationdb) foundationdb; + + nativeCheckInputs = [ + openssl + ]; + + buildNoDefaultFeatures = true; + buildFeatures = [ + "sqlite" + "postgres" + "mysql" + "rocks" + "s3" + "redis" + "azure" + "nats" + ] + ++ lib.optionals withFoundationdb [ "foundationdb" ] + ++ lib.optionals stalwartEnterprise [ "enterprise" ]; + + env = { + OPENSSL_NO_VENDOR = true; + ZSTD_SYS_USE_PKG_CONFIG = true; + ROCKSDB_INCLUDE_DIR = "${rocksdb}/include"; + ROCKSDB_LIB_DIR = "${rocksdb}/lib"; + } + // + lib.optionalAttrs + (stdenv.hostPlatform.isLinux && (stdenv.hostPlatform.isAarch64 || stdenv.hostPlatform.isArmv7)) + { + JEMALLOC_SYS_WITH_LG_PAGE = 16; + }; + + postInstall = '' + mkdir -p $out/etc/stalwart + + mkdir -p $out/lib/systemd/system + + substitute resources/systemd/stalwart-mail.service $out/lib/systemd/system/stalwart.service \ + --replace-fail "__PATH__" "$out" + ''; + + preCheck = '' + export STORE=Sqlite + ''; + checkFlags = lib.forEach [ + # Require running mysql, postgresql daemon + "directory::imap::imap_directory" + "directory::internal::internal_directory" + "directory::ldap::ldap_directory" + "directory::sql::sql_directory" + "directory::oidc::oidc_directory" + "store::blob::blob_tests" + "store::lookup::lookup_tests" + "smtp::lookup::sql::lookup_sql" + # thread 'directory::smtp::lmtp_directory' panicked at tests/src/store/mod.rs:122:44: + # called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" } + "directory::smtp::lmtp_directory" + # thread 'imap::imap_tests' panicked at tests/src/imap/mod.rs:436:14: + # Missing store type. Try running `STORE=<store_type> cargo test`: NotPresent + "imap::imap_tests" + # thread 'jmap::jmap_tests' panicked at tests/src/jmap/mod.rs:303:14: + # Missing store type. Try running `STORE=<store_type> cargo test`: NotPresent + "jmap::jmap_tests" + # Failed to read system DNS config: io error: No such file or directory (os error 2) + "smtp::inbound::data::data" + # Expected "X-My-Header: true" but got Received: from foobar.net (unknown [10.0.0.123]) + "smtp::inbound::scripts::sieve_scripts" + # thread 'smtp::outbound::lmtp::lmtp_delivery' panicked at tests/src/smtp/session.rs:313:13: + # Expected "<invalid@domain.org> (failed to lookup" but got From: "Mail Delivery Subsystem" <MAILER-DAEMON@localhost> + "smtp::outbound::lmtp::lmtp_delivery" + # thread 'smtp::outbound::extensions::extensions' panicked at tests/src/smtp/inbound/mod.rs:45:23: + # No queue event received. + "smtp::outbound::extensions::extensions" + # panicked at tests/src/smtp/outbound/smtp.rs:173:5: + "smtp::outbound::smtp::smtp_delivery" + # panicked at tests/src/smtp/outbound/lmtp.rs + "smtp::outbound::lmtp::lmtp_delivery" + # thread 'smtp::queue::retry::queue_retry' panicked at tests/src/smtp/queue/retry.rs:119:5: + # assertion `left == right` failed + # left: [1, 2, 2] + # right: [1, 2, 3] + "smtp::queue::retry::queue_retry" + # thread 'smtp::queue::virtualq::virtual_queue' panicked at /build/source/crates/store/src/dispatch/store.rs:548:14: + # called `Result::unwrap()` on an `Err` value: Error(Event { inner: Store(MysqlError), keys: [(Reason, String("Input/output error: Input/output error: Connection refused (os error 111)")), (CausedBy, String("crates/store/src/dispatch/store.rs:301"))] }) + "smtp::queue::virtualq::virtual_queue" + # Missing store type. Try running `STORE=<store_type> cargo test`: NotPresent + "store::store_tests" + # Missing store type. Try running `STORE=<store_type> cargo test`: NotPresent + "cluster::cluster_tests" + # Missing store type. Try running `STORE=<store_type> cargo test`: NotPresent + "webdav::webdav_tests" + # thread 'config::parser::tests::toml_parse' panicked at crates/utils/src/config/parser.rs:463:58: + # called `Result::unwrap()` on an `Err` value: "Expected ['\\n'] but found '!' in value at line 70." + "config::parser::tests::toml_parse" + # error[E0432]: unresolved import `r2d2_sqlite` + # use of undeclared crate or module `r2d2_sqlite` + "backend::sqlite::pool::SqliteConnectionManager::with_init" + # thread 'smtp::reporting::analyze::report_analyze' panicked at tests/src/smtp/reporting/analyze.rs:88:5: + # assertion `left == right` failed + # left: 0 + # right: 12 + "smtp::reporting::analyze::report_analyze" + # thread 'smtp::inbound::dmarc::dmarc' panicked at tests/src/smtp/inbound/mod.rs:59:26: + # Expected empty queue but got Reload + "smtp::inbound::dmarc::dmarc" + # thread 'smtp::queue::concurrent::concurrent_queue' panicked at tests/src/smtp/inbound/mod.rs:65:9: + # assertion `left == right` failed + "smtp::queue::concurrent::concurrent_queue" + # Failed to read system DNS config: io error: No such file or directory (os error 2) + "smtp::inbound::auth::auth" + # Failed to read system DNS config: io error: No such file or directory (os error 2) + "smtp::inbound::antispam::antispam" + # Failed to read system DNS config: io error: No such file or directory (os error 2) + "smtp::inbound::vrfy::vrfy_expn" + # thread 'smtp::management::queue::manage_queue' panicked at tests/src/smtp/inbound/mod.rs:45:23: + # No queue event received. + # NOTE: Test unreliable on high load systems + "smtp::management::queue::manage_queue" + # thread 'responses::tests::parse_responses' panicked at crates/dav-proto/src/responses/mod.rs:671:17: + # assertion `left == right` failed: failed for 008.xml + # left: ElementEnd + # right: Bytes([...]) + "responses::tests::parse_responses" + # thread 'store::search_tests' (912386) panicked at tests/src/store/mod.rs:116:10: + # Missing store type. Try running `STORE=<store_type> cargo test`: NotPresent + "store::search_tests" + ] (test: "--skip=${test}"); + + doCheck = !(stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isAarch64); + + __darwinAllowLocalNetworking = true; + + passthru = { + inherit rocksdb; + # webadmin = buildPackages.callPackage ./webadmin.nix {}; + # spam-filter = callPackage ./spam-filter.nix {}; + updateScript = nix-update-script { }; + # test.stalwart = nixosTests.stalwart; + }; + + meta = { + description = "Secure, modern, all-in-one mail and collaboration server"; + longDescription = '' + Secure, scalable and fluent in every protocol (IMAP, JMAP, SMTP, CalDAV, CardDAV, WebDAV). + ''; + homepage = "https://github.com/stalwartlabs/stalwart"; + changelog = "https://github.com/stalwartlabs/stalwart/blob/main/CHANGELOG.md"; + license = [ + lib.licenses.agpl3Only + ] + ++ lib.optionals stalwartEnterprise [ + { + fullName = "Stalwart Enterprise License 1.0 (SELv1) Agreement"; + url = "https://github.com/stalwartlabs/stalwart/blob/main/LICENSES/LicenseRef-SEL.txt"; + free = false; + redistributable = false; + } + ]; + + mainProgram = "stalwart"; + }; +}) + diff --git a/packages/stalwart/spam-filter.nix b/packages/stalwart/spam-filter.nix new file mode 100644 index 0000000..5497322 --- /dev/null +++ b/packages/stalwart/spam-filter.nix @@ -0,0 +1,42 @@ +{ + lib, + fetchFromGithub, + stdenv, + stalwart, + nix-update-script, +}: stdenv.mkDerivation (finalAttrs: { + pname = "spam-filter"; + version = "2.0.5"; + + src = fetchFromGithub { + owner = "stalwartlabs"; + repo = "spam-filter"; + tag = "v${finalAttrs.version}"; + hash = ""; + }; + + buildPhase = '' + bash ./build.sh + ''; + + installPhase = '' + mkdir -p $out + cp spam-filter.toml $out/ + ''; + + passthru = {updateScript = nix-update-script {};}; + + meta = { + description = "Spam filter module for the Stalwart server"; + homepage = "https://github.com/stalwartlabs/spam-filter"; + changelog = "https://github.com/stalwartlabs/spam-filter/blob/${finalAttrs.src.tag}/CHANGELOG.md"; + license = with lib.licenses; [ + mit + asl20 + ]; + # inherit (stalwart.meta) maintainers; + }; + + +}) + diff --git a/packages/stalwart/webadmin.nix b/packages/stalwart/webadmin.nix new file mode 100644 index 0000000..0035bda --- /dev/null +++ b/packages/stalwart/webadmin.nix @@ -0,0 +1,77 @@ +{ + lib, + rustPlatform, + stalwart, + fetchFromGitHub, + trunk, + tailwindcss_3, + fetchNpmDeps, + nix-update-script, + nodejs, + npmHooks, + llvmPackages, + wasm-bindgen-cli_0_2_93, + binaryen, + zip, +}: + +rustPlatform.buildRustPackage (finalAttrs: { + pname = "webadmin"; + version = "0.1.37"; + + src = fetchFromGitHub { + owner = "stalwartlabs"; + repo = "webadmin"; + tag = "v${finalAttrs.version}"; + hash = ""; + }; + + npmDeps = fetchNpmDeps { + name = "${finalAttrs.pname}-npm-deps"; + hash = ""; + }; + + cargoHash = ""; + + postPatch = '' + # Using local tailwindcss for compilation + substituteInPlace Trunk.toml --replace-fail "npx tailwindcss" "tailwindcss" + ''; + + nativeBuildInputs = [ + binaryen + llvmPackages.bintools-unwrapped + nodejs + npmHooks.npmConfigHook + tailwindcss_3 + trunk + # needs to match with wasm-bindgen version in upstreams Cargo.lock + wasm-bindgen-cli_0_2_93 + + zip + ]; + + env.NODE_PATH = "$npmDeps"; + + buildPhase = '' + trunk build --offline --frozen --release + ''; + + installPhase = '' + cd dist + mkdir -p $out + zip -r $out/webadmin.zip * + ''; + + passthru = { + updateScript = nix-update-script { }; + }; + + meta = { + description = "Web administration module for the Stalwart server"; + homepage = "https://github.com/stalwartlabs/webadmin"; + changelog = "https://github.com/stalwartlabs/webadmin/blob/${finalAttrs.src.tag}/CHANGELOG.md"; + license = lib.licenses.agpl3Only; + # inherit (stalwart.meta) maintainers; + }; +}) |
