Skip to content
Draft
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ end_of_line = lf
[pkg/PKGBUILD]
end_of_line = lf

[*.rb]
[*.{rb,nix}]
end_of_line = lf
indent_size = 2
indent_style = space
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*.zst

demo/
result/

*.snap
k8s/charts/meerkat-dsa/*.tgz
Expand Down
51 changes: 51 additions & 0 deletions apps/meerkat-docs/docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,57 @@ Run `brew uninstall meerkat_dsa` to uninstall it from your system.

Run `brew test -d meerkat_dsa` to run tests after it is installed.

### Nix Package

First, ensure that `pkg/default.nix` is moved to the root of this repository:
in other words, it should be in the same folder as `nx.json`. Then run:

```bash
nix-build -E '(import <nixpkgs> {}).callPackage ./default.nix {}'
```

I don't really know why that is needed. Why doesn't it "just work"(tm)?

Then, your build outputs will be symlinked to `./result`. Just poke around in
there: you'll get it.

To test the Systemd service (which is a separate package), it seems like you
have to have NixOS. However, you can do a little pre-validation on it like so:

```bash
nix-instantiate --parse pkg/meerkat-dsa.nix
```

Then you can do a little more validation like so:

```bash
nix-instantiate '<nixpkgs/nixos>' -A config.systemd.services.meerkat-dsa -I nixos-config=./pkg/meerkat-dsa.nix
```

If you see

```
error: attribute 'meerkat-dsa' in selection path 'config.systemd.services.meerkat-dsa' not found
```

try removing `lib.mkIf cfg.enable` from `meerkat-dsa.nix`.

### UPDATE ON NIX

Creating the Nix package wasn't too hard. Actually, it was one of the easiest
packagings I have done so far! But using a Flake on NixOS, wiring up the
Systemd service, etc. is from Hell. I had to write so much Nix "code" to still
have problem after problem. One remaining problem I have is `pkgs.meerkat-dsa`
not being defined. I can try to get this working with an overlay, but that is
not how this would really be used once a proper Nix package is published; doing
so would make this whole thing a lot simpler.

So I have decided on this: I am going to release Meerkat DSA 4.0.0 without a
Nix package. Then, once I have the commit hash, I am going to submit a PR to
get a Nix package published for Meerkat DSA. Once that's out, then I will work
on the OS module, flake, whatever. If that doesn't work out, or if I never get
to it, too bad: stop being so damn difficult.

## CI

[Here](https://github.com/actions/runner-images) are the different runners
Expand Down
40 changes: 40 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
description = "Meerkat X.500 Directory System Agent (DSA) and LDAP Server";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};

outputs = { self, nixpkgs }:
let
systems = [ "x86_64-linux" ];
forAllSystems = f:
nixpkgs.lib.genAttrs systems (system:
f {
inherit system;
pkgs = import nixpkgs {
inherit system;
overlays = [ self.overlays.default ];
};
}
);
in {
packages = forAllSystems ({ pkgs, ... }: {
default = pkgs.meerkat-dsa;
meerkat-dsa = pkgs.meerkat-dsa;
});

apps = forAllSystems ({ pkgs, ... }: {
default = {
type = "app";
program = "${pkgs.meerkat-dsa}/bin/meerkat";
};
});

overlays.default = import ./pkg/overlay.nix;
nixosModules.meerkat-dsa = import ./pkg/meerkat-dsa.nix;
checks = forAllSystems ({ pkgs, ... }: {
build = pkgs.meerkat-dsa;
});
};
}
82 changes: 82 additions & 0 deletions pkg/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{ lib
, stdenv
, nodejs_24
, buildNpmPackage
, fetchFromGitHub
}:

let
buildStage = buildNpmPackage {
pname = "meerkat-dsa-build";
version = "4.0.0";
src = fetchFromGitHub {
owner = "Wildboar-Software";
repo = "directory";
rev = "v4.0.0-rc1";
hash = "sha256-n26A/OtmRuMcnrihSl1b+YFKd23EIg2gsXKRC+AZsq8=";
};
npmDepsHash = "sha256-eih0APtkKpYzJenDP+xNHkfmQ6ynbO57fXRemaFzEHo=";
makeCacheWritable = true;
npmFlags = [ "--no-audit" "--no-fund" "--no-save" "--ignore-scripts" "--verbose" "--legacy-peer-deps" ];
buildPhase = ''
npx nx \
--tuiAutoExit=true \
--outputStyle=static \
run meerkat:build \
--skipNxCache \
--skipRemoteCache \
--skip-nx-cache \
--verbose
'';
installPhase = ''
cp -r dist/apps/meerkat $out
cp doc/man/man1/meerkat-dsa.1 $out
cp doc/man/man5/meerkat.env.5 $out
'';
};

runtimeStage = buildNpmPackage {
pname = "meerkat-dsa";
version = "4.0.0";
src = buildStage;
npmDepsHash = "sha256-uP0+7G8ujB9aG62za4+3t+X6EWaxoGFf/xZZhf/47jw=";
npmFlags = [ "--no-audit" "--no-fund" "--no-save" "--ignore-scripts" "--verbose" ];
dontNpmBuild = true;
installPhase = ''
mkdir -p $out/lib
cp -r * $out/lib
cp prisma/prisma.config.ts $out/lib
mkdir -p $out/bin
# This will overwrite the bin that buildNpmPackage creates.
cat > $out/bin/meerkat <<'EOF'
#!${stdenv.shell}
set -euo pipefail

# If the migration fails, still carry on: we do not want a failed migration
# (which is infrequently needed to begin with) to make us unable to start
# Meerkat DSA
#
# NOTE: Prisma seems to search for migrations relative to the config file, not
# the current directory.
PRISMA_HIDE_UPDATE_MESSAGE=1 ${nodejs_24}/bin/npx prisma migrate deploy \
--schema @APP_DIR@/lib/prisma/schema.prisma \
--config @APP_DIR@/lib/prisma.config.ts || true

exec ${nodejs_24}/bin/node @APP_DIR@/lib/main.js start "$@"
EOF
substituteInPlace $out/bin/meerkat --replace "@APP_DIR@" "$out"
chmod +x $out/bin/meerkat
mkdir -p $out/share/man/man1
mkdir -p $out/share/man/man5
install -m 644 meerkat-dsa.1 $out/share/man/man1/meerkat-dsa.1
install -m 644 meerkat.env.5 $out/share/man/man5/meerkat.env.5
'';
meta = with lib; {
description = "Meerkat X.500 Directory System Agent (DSA) and LDAP Server";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "meerkat";
};
};
in
runtimeStage
75 changes: 75 additions & 0 deletions pkg/meerkat-dsa.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{ config, lib, pkgs, ... }:

let
cfg = config.services.meerkat-dsa;
in {
options.services.meerkat-dsa = {
enable = lib.mkEnableOption "Meerkat X.500 Directory System Agent (DSA) and LDAP Server";
dataDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/meerkat";
};

environmentFile = lib.mkOption {
type = lib.types.path;
default = "/etc/meerkat/meerkat.env";
description = "Environment file (using .env syntax)";
};
};

config = lib.mkIf cfg.enable {

users.users.meerkat = {
isSystemUser = true;
group = "meerkat";
};

users.groups.meerkat = {};

# Documented here: https://github.com/NixOS/nixos/blob/5f444a4d8d49a497bcfabe2544bda264c845653e/modules/system/boot/systemd-unit-options.nix
# Example application: https://github.com/DMarby/picsum-photos/blob/a4359f9d85e99aaf11a110590a681510e21130c4/flake.nix#L178
systemd.services.meerkat-dsa = {
description = "Meerkat DSA";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
# This seems to be required even though undocumented.
startLimitBurst = 10;
# This seems to be required even though undocumented.
startLimitIntervalSec = 5;
serviceConfig = {
Type = "simple";
User = "meerkat";
Group = "meerkat";
ExecStart = "${pkgs.meerkat-dsa}/bin/meerkat";
Restart = "on-failure";
RestartSec = "30s";
WorkingDirectory = cfg.dataDir;
EnvironmentFile = cfg.environmentFile;
PassEnvironment = "LANG NO_COLOR";
NoNewPrivileges = "yes";
ProtectSystem = "full";
ProtectHome = "yes";
ProtectProc = "invisible";
PrivateTmp = "yes";
PrivateDevices = "yes";
PrivateUsers = "self";
SecureBits = "";
ProtectClock = "yes";
ProtectHostname = "yes";
ProtectKernelModules = "yes";
ProtectKernelLogs = "yes";
ProtectControlGroups = "yes";
RestrictRealtime = "yes";
PrivateMounts = "yes";
SystemCallFilter="~@cpu-emuation @chown @debug @keyring @module @mount @obsolete @privileged @reboot @resources @setuid @swap";
LogNamespace = "meerkat";
};
environment = {
NODE_ENV = "production";
DATABASE_URL = "file:${cfg.dataDir}/meerkat.db";
PRISMA_HIDE_UPDATE_MESSAGE = "1";
MEERKAT_LOG_SYSTEMD_LEVEL_PREFIX = "1";
};
};
};
}
3 changes: 3 additions & 0 deletions pkg/overlay.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
final: prev: {
meerkat-dsa = prev.callPackage ./default.nix {};
}