karakeep: init
This commit is contained in:
parent
139ceca768
commit
63b7b09a0f
6 changed files with 545 additions and 4 deletions
|
|
@ -163,6 +163,8 @@ Also, the stack fits together nicely thanks to [contracts](#contracts).
|
||||||
- Hledger
|
- Hledger
|
||||||
- Home-Assistant
|
- Home-Assistant
|
||||||
- Jellyfin
|
- Jellyfin
|
||||||
|
- Karakeep
|
||||||
|
- Open WebUI
|
||||||
- Pinchflat
|
- Pinchflat
|
||||||
- Vaultwarden
|
- Vaultwarden
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@
|
||||||
];
|
];
|
||||||
"services/home-assistant" = ./modules/services/home-assistant.nix;
|
"services/home-assistant" = ./modules/services/home-assistant.nix;
|
||||||
"services/jellyfin" = ./modules/services/jellyfin.nix;
|
"services/jellyfin" = ./modules/services/jellyfin.nix;
|
||||||
|
"services/karakeep" = ./modules/services/karakeep.nix;
|
||||||
"services/nextcloud-server" = {
|
"services/nextcloud-server" = {
|
||||||
module = ./modules/services/nextcloud-server.nix;
|
module = ./modules/services/nextcloud-server.nix;
|
||||||
optionRoot = [ "shb" "nextcloud" ];
|
optionRoot = [ "shb" "nextcloud" ];
|
||||||
|
|
@ -218,6 +219,7 @@
|
||||||
// (vm_test "immich" ./test/services/immich.nix)
|
// (vm_test "immich" ./test/services/immich.nix)
|
||||||
// (vm_test "homeassistant" ./test/services/home-assistant.nix)
|
// (vm_test "homeassistant" ./test/services/home-assistant.nix)
|
||||||
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
||||||
|
// (vm_test "karakeep" ./test/services/karakeep.nix)
|
||||||
// (vm_test "monitoring" ./test/services/monitoring.nix)
|
// (vm_test "monitoring" ./test/services/monitoring.nix)
|
||||||
// (vm_test "nextcloud" ./test/services/nextcloud.nix)
|
// (vm_test "nextcloud" ./test/services/nextcloud.nix)
|
||||||
// (vm_test "open-webui" ./test/services/open-webui.nix)
|
// (vm_test "open-webui" ./test/services/open-webui.nix)
|
||||||
|
|
@ -312,6 +314,7 @@
|
||||||
self.nixosModules.immich
|
self.nixosModules.immich
|
||||||
self.nixosModules.home-assistant
|
self.nixosModules.home-assistant
|
||||||
self.nixosModules.jellyfin
|
self.nixosModules.jellyfin
|
||||||
|
self.nixosModules.karakeep
|
||||||
self.nixosModules.nextcloud-server
|
self.nixosModules.nextcloud-server
|
||||||
self.nixosModules.open-webui
|
self.nixosModules.open-webui
|
||||||
self.nixosModules.pinchflat
|
self.nixosModules.pinchflat
|
||||||
|
|
@ -343,6 +346,7 @@
|
||||||
nixosModules.immich = modules/services/immich.nix;
|
nixosModules.immich = modules/services/immich.nix;
|
||||||
nixosModules.home-assistant = modules/services/home-assistant.nix;
|
nixosModules.home-assistant = modules/services/home-assistant.nix;
|
||||||
nixosModules.jellyfin = modules/services/jellyfin.nix;
|
nixosModules.jellyfin = modules/services/jellyfin.nix;
|
||||||
|
nixosModules.karakeep = modules/services/karakeep.nix;
|
||||||
nixosModules.nextcloud-server = modules/services/nextcloud-server.nix;
|
nixosModules.nextcloud-server = modules/services/nextcloud-server.nix;
|
||||||
nixosModules.open-webui = modules/services/open-webui.nix;
|
nixosModules.open-webui = modules/services/open-webui.nix;
|
||||||
nixosModules.pinchflat = modules/services/pinchflat.nix;
|
nixosModules.pinchflat = modules/services/pinchflat.nix;
|
||||||
|
|
|
||||||
224
modules/services/karakeep.nix
Normal file
224
modules/services/karakeep.nix
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.shb.karakeep;
|
||||||
|
|
||||||
|
contracts = pkgs.callPackage ../contracts {};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../blocks/nginx.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
options.shb.karakeep = {
|
||||||
|
enable = lib.mkEnableOption "the Karakeep service";
|
||||||
|
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Subdomain under which Karakeep will be served.";
|
||||||
|
default = "karakeep";
|
||||||
|
};
|
||||||
|
|
||||||
|
domain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "domain under which Karakeep will be served.";
|
||||||
|
example = "mydomain.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
ssl = lib.mkOption {
|
||||||
|
description = "Path to SSL files";
|
||||||
|
type = lib.types.nullOr contracts.ssl.certs;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
description = "Port Karakeep listens to incoming requests.";
|
||||||
|
default = 3000;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment = lib.mkOption {
|
||||||
|
default = {};
|
||||||
|
type = lib.types.attrsOf lib.types.str;
|
||||||
|
description = "Extra environment variables. See https://docs.karakeep.app/configuration/";
|
||||||
|
example = ''
|
||||||
|
{
|
||||||
|
OLLAMA_BASE_URL = "http://127.0.0.1:''${toString config.services.ollama.port}";
|
||||||
|
INFERENCE_TEXT_MODEL = "deepseek-r1:1.5b";
|
||||||
|
INFERENCE_IMAGE_MODEL = "llava";
|
||||||
|
EMBEDDING_TEXT_MODEL = "nomic-embed-text:v1.5";
|
||||||
|
INFERENCE_ENABLE_AUTO_SUMMARIZATION = "true";
|
||||||
|
INFERENCE_JOB_TIMEOUT_SEC = "200";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Setup LDAP integration.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
userGroup = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Group users must belong to to be able to login.";
|
||||||
|
default = "karakeep_user";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sso = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Setup SSO integration.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
enable = lib.mkEnableOption "SSO integration.";
|
||||||
|
|
||||||
|
authEndpoint = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Endpoint to the SSO provider. Leave null to not have SSO configured.";
|
||||||
|
example = "https://authelia.example.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
clientID = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Client ID for the OIDC endpoint.";
|
||||||
|
default = "karakeep";
|
||||||
|
};
|
||||||
|
|
||||||
|
authorization_policy = lib.mkOption {
|
||||||
|
type = lib.types.enum [ "one_factor" "two_factor" ];
|
||||||
|
description = "Require one factor (password) or two factor (device) authentication.";
|
||||||
|
default = "one_factor";
|
||||||
|
};
|
||||||
|
|
||||||
|
nextauthSecret = lib.mkOption {
|
||||||
|
description = "NextAuth secret.";
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = contracts.secret.mkRequester {
|
||||||
|
owner = "karakeep";
|
||||||
|
restartUnits = [ "karakeep.service" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sharedSecret = lib.mkOption {
|
||||||
|
description = "OIDC shared secret for Karakeep.";
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = contracts.secret.mkRequester {
|
||||||
|
owner = "karakeep";
|
||||||
|
restartUnits = [ "karakeep.service" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sharedSecretForAuthelia = lib.mkOption {
|
||||||
|
description = "OIDC shared secret for Authelia. Must be the same as `sharedSecret`";
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = contracts.secret.mkRequester {
|
||||||
|
mode = "0400";
|
||||||
|
ownerText = "config.shb.authelia.autheliaUser";
|
||||||
|
owner = config.shb.authelia.autheliaUser;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
backup = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Backup state directory.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = contracts.backup.mkRequester {
|
||||||
|
user = "karakeep";
|
||||||
|
sourceDirectories = [
|
||||||
|
"/var/lib/karakeep"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = (lib.mkMerge [
|
||||||
|
(lib.mkIf cfg.enable {
|
||||||
|
services.karakeep = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
extraEnvironment = {
|
||||||
|
PORT = toString cfg.port;
|
||||||
|
DISABLE_NEW_RELEASE_CHECK = "true"; # These are handled by NixOS
|
||||||
|
} // cfg.environment;
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.nginx.vhosts = [
|
||||||
|
{
|
||||||
|
inherit (cfg) subdomain domain ssl;
|
||||||
|
upstream = "http://127.0.0.1:${toString cfg.port}/";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
})
|
||||||
|
(lib.mkIf (cfg.enable && cfg.sso.enable) {
|
||||||
|
shb.lldap.ensureGroups = {
|
||||||
|
${cfg.ldap.userGroup} = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.authelia.extraOidcAuthorizationPolicies.karakeep = {
|
||||||
|
default_policy = "deny";
|
||||||
|
rules = [
|
||||||
|
{
|
||||||
|
subject = [ "group:${cfg.ldap.userGroup}" ];
|
||||||
|
policy = cfg.sso.authorization_policy;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
shb.authelia.oidcClients = [
|
||||||
|
{
|
||||||
|
client_id = cfg.sso.clientID;
|
||||||
|
client_secret.source = cfg.sso.sharedSecretForAuthelia.result.path;
|
||||||
|
scopes = [ "openid" "email" "profile" ];
|
||||||
|
authorization_policy = "karakeep";
|
||||||
|
redirect_uris = [
|
||||||
|
"https://${cfg.subdomain}.${cfg.domain}/api/auth/callback/custom"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services.karakeep = {
|
||||||
|
extraEnvironment = {
|
||||||
|
DISABLE_SIGNUPS = "false";
|
||||||
|
DISABLE_PASSWORD_AUTH = "true";
|
||||||
|
NEXTAUTH_URL = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
OAUTH_WELLKNOWN_URL = "${cfg.sso.authEndpoint}/.well-known/openid-configuration";
|
||||||
|
OAUTH_PROVIDER_NAME = "Single Sign-On";
|
||||||
|
OAUTH_CLIENT_ID = cfg.sso.clientID;
|
||||||
|
OAUTH_SCOPE = "openid email profile";
|
||||||
|
};
|
||||||
|
environmentFile = "/run/karakeep/secrets.env";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d '/run/karakeep' 0750 root root - -"
|
||||||
|
];
|
||||||
|
systemd.services.karakeep-pre = {
|
||||||
|
script = lib.shb.replaceSecrets {
|
||||||
|
userConfig = {
|
||||||
|
NEXTAUTH_SECRET.source = cfg.sso.nextauthSecret.result.path;
|
||||||
|
OAUTH_CLIENT_SECRET.source = cfg.sso.sharedSecret.result.path;
|
||||||
|
};
|
||||||
|
resultPath = "/run/karakeep/secrets.env";
|
||||||
|
generator = lib.shb.toEnvVar;
|
||||||
|
};
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
before = [ "karakeep-web.service" "karakeep-workers.service" ];
|
||||||
|
requiredBy = [ "karakeep-web.service" "karakeep-workers.service" ];
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
110
modules/services/karakeep/docs/default.md
Normal file
110
modules/services/karakeep/docs/default.md
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
# Karakeep {#services-karakeep}
|
||||||
|
|
||||||
|
Defined in [`/modules/blocks/karakeep.nix`](@REPO@/modules/blocks/karakeep.nix),
|
||||||
|
found in the `selfhostblocks.nixosModules.karakeep` module.
|
||||||
|
See [the manual](usage.html#usage-flake) for how to import the module in your code.
|
||||||
|
|
||||||
|
This service sets up [Karakeep][] which is a bookmarking service powered by LLMs.
|
||||||
|
It integrates well with [Ollama][].
|
||||||
|
|
||||||
|
[Karakeep]: https://github.com/karakeep-app/karakeep
|
||||||
|
[Ollama]: https://ollama.com/
|
||||||
|
|
||||||
|
## Features {#services-karakeep-features}
|
||||||
|
|
||||||
|
- Declarative [LDAP](#services-karakeep-options-shb.karakeep.ldap) Configuration.
|
||||||
|
- Needed LDAP groups are created automatically.
|
||||||
|
- Declarative [SSO](#services-karakeep-options-shb.karakeep.sso) Configuration.
|
||||||
|
- When SSO is enabled, login with user and password is disabled.
|
||||||
|
- Registration is enabled through SSO.
|
||||||
|
- Access through [subdomain](#services-karakeep-options-shb.karakeep.subdomain) using reverse proxy.
|
||||||
|
- Access through [HTTPS](#services-karakeep-options-shb.karakeep.ssl) using reverse proxy.
|
||||||
|
- [Backup](#services-karakeep-options-shb.karakeep.sso) through the [backup block](./blocks-backup.html).
|
||||||
|
|
||||||
|
## Usage {#services-karakeep-usage}
|
||||||
|
|
||||||
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
- the [`shb.ssl` block](blocks-ssl.html#usage),
|
||||||
|
- the [`shb.lldap` block](blocks-lldap.html#blocks-lldap-global-setup).
|
||||||
|
- the [`shb.authelia` block](blocks-authelia.html#blocks-sso-global-setup).
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.karakeep = {
|
||||||
|
enable = true;
|
||||||
|
domain = "example.com";
|
||||||
|
subdomain = "karakeep";
|
||||||
|
|
||||||
|
ssl = config.shb.certs.certs.letsencrypt.${domain};
|
||||||
|
|
||||||
|
sso = {
|
||||||
|
enable = true;
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
|
||||||
|
nextauthSecret.result = config.shb.sops.secret.nextauthSecret.result;
|
||||||
|
sharedSecret.result = config.shb.sops.secret.oidcSecret.result;
|
||||||
|
sharedSecretForAuthelia.result = config.shb.sops.secret.oidcAutheliaSecret.result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.sops.secret.nextauthSecret.request = config.shb.karakeep.sso.sharedSecret.request;
|
||||||
|
shb.sops.secret.oidcSecret.request = config.shb.karakeep.sso.sharedSecret.request;
|
||||||
|
shb.sops.secret.oidcAutheliaSecret = {
|
||||||
|
request = config.shb.karakeep.sso.sharedSecretForAuthelia.request;
|
||||||
|
settings.key = oidcSecret;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Secrets can be randomly generated with `nix run nixpkgs#openssl -- rand -hex 64`.
|
||||||
|
|
||||||
|
The [user](#services-open-webui-options-shb.open-webui.ldap.userGroup)
|
||||||
|
and [admin](#services-open-webui-options-shb.open-webui.ldap.adminGroup)
|
||||||
|
LDAP groups are created automatically.
|
||||||
|
|
||||||
|
## Integration with Ollama {#services-karakeep-ollama}
|
||||||
|
|
||||||
|
Assuming ollama is enabled, it will be available on port `config.services.ollama.port`.
|
||||||
|
The following snippet sets up acceleration using an AMD (i)GPU and loads some models.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
services.ollama = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# https://wiki.nixos.org/wiki/Ollama#AMD_GPU_with_open_source_driver
|
||||||
|
acceleration = "rocm";
|
||||||
|
|
||||||
|
# https://ollama.com/library
|
||||||
|
loadModels = [
|
||||||
|
"deepseek-r1:1.5b"
|
||||||
|
"llama3.2:3b"
|
||||||
|
"llava:7b"
|
||||||
|
"mxbai-embed-large:335m"
|
||||||
|
"nomic-embed-text:v1.5"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Integrating with the ollama service is done with:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
services.open-webui = {
|
||||||
|
environment.OLLAMA_BASE_URL = "http://127.0.0.1:${toString config.services.ollama.port}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice we're using the upstream service here `services.open-webui`, not `shb.open-webui`.
|
||||||
|
|
||||||
|
## Options Reference {#services-karakeep-options}
|
||||||
|
|
||||||
|
```{=include=} options
|
||||||
|
id-prefix: services-karakeep-options-
|
||||||
|
list-id: selfhostblocks-services-karakeep-options
|
||||||
|
source: @OPTIONS_JSON@
|
||||||
|
```
|
||||||
|
|
@ -13,11 +13,11 @@ This service sets up [Open WebUI][] which provides a frontend to various LLMs.
|
||||||
- Telemetry disabled.
|
- Telemetry disabled.
|
||||||
- Skip onboarding through custom patch.
|
- Skip onboarding through custom patch.
|
||||||
- Declarative [LDAP](#services-open-webui-options-shb.open-webui.ldap) Configuration.
|
- Declarative [LDAP](#services-open-webui-options-shb.open-webui.ldap) Configuration.
|
||||||
Needed LDAP groups are created automatically.
|
- Needed LDAP groups are created automatically.
|
||||||
- Declarative [SSO](#services-open-webui-options-shb.open-webui.sso) Configuration.
|
- Declarative [SSO](#services-open-webui-options-shb.open-webui.sso) Configuration.
|
||||||
When SSO is enabled, login with user and password is disabled.
|
- When SSO is enabled, login with user and password is disabled.
|
||||||
Registration is enabled through SSO.
|
- Registration is enabled through SSO.
|
||||||
Correct error message for unauthorized user through custom patch.
|
- Correct error message for unauthorized user through custom patch.
|
||||||
- Access through [subdomain](#services-open-webui-options-shb.open-webui.subdomain) using reverse proxy.
|
- Access through [subdomain](#services-open-webui-options-shb.open-webui.subdomain) using reverse proxy.
|
||||||
- Access through [HTTPS](#services-open-webui-options-shb.open-webui.ssl) using reverse proxy.
|
- Access through [HTTPS](#services-open-webui-options-shb.open-webui.ssl) using reverse proxy.
|
||||||
- [Backup](#services-open-webui-options-shb.open-webui.sso) through the [backup block](./blocks-backup.html).
|
- [Backup](#services-open-webui-options-shb.open-webui.sso) through the [backup block](./blocks-backup.html).
|
||||||
|
|
|
||||||
201
test/services/karakeep.nix
Normal file
201
test/services/karakeep.nix
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
nextauthSecret = "nextauthSecret";
|
||||||
|
oidcSecret = "oidcSecret";
|
||||||
|
|
||||||
|
testLib = pkgs.callPackage ../common.nix {};
|
||||||
|
|
||||||
|
commonTestScript = testLib.mkScripts {
|
||||||
|
hasSSL = { node, ... }: !(isNull node.config.shb.karakeep.ssl);
|
||||||
|
waitForServices = { ... }: [
|
||||||
|
"karakeep-web.service"
|
||||||
|
"karakeep-workers.service"
|
||||||
|
"nginx.service"
|
||||||
|
];
|
||||||
|
waitForPorts = { node, ... }: [
|
||||||
|
node.config.shb.karakeep.port
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
basic = { config, ... }: {
|
||||||
|
imports = [
|
||||||
|
testLib.baseModule
|
||||||
|
../../modules/blocks/hardcodedsecret.nix
|
||||||
|
../../modules/blocks/lldap.nix
|
||||||
|
../../modules/services/karakeep.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
test = {
|
||||||
|
subdomain = "k";
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.karakeep = {
|
||||||
|
enable = true;
|
||||||
|
inherit (config.test) subdomain domain;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.hosts = {
|
||||||
|
"127.0.0.1" = [ "${config.test.subdomain}.${config.test.domain}" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
https = { config, ... }: {
|
||||||
|
shb.karakeep = {
|
||||||
|
ssl = config.shb.certs.certs.selfsigned.n;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap = { config, ... }: {
|
||||||
|
shb.karakeep = {
|
||||||
|
ldap = {
|
||||||
|
userGroup = "user_group";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
clientLoginSso = { config, ... }: {
|
||||||
|
imports = [
|
||||||
|
testLib.baseModule
|
||||||
|
testLib.clientLoginModule
|
||||||
|
];
|
||||||
|
test = {
|
||||||
|
subdomain = "k";
|
||||||
|
};
|
||||||
|
|
||||||
|
test.login = {
|
||||||
|
startUrl = "https://${config.test.fqdn}";
|
||||||
|
beforeHook = ''
|
||||||
|
page.get_by_role("button", name="single sign-on").click()
|
||||||
|
'';
|
||||||
|
usernameFieldLabelRegex = "Username";
|
||||||
|
passwordFieldLabelRegex = "Password";
|
||||||
|
loginButtonNameRegex = "[sS]ign [iI]n";
|
||||||
|
testLoginWith = [
|
||||||
|
{ username = "alice"; password = "NotAlicePassword"; nextPageExpect = [
|
||||||
|
"expect(page.get_by_text(re.compile('[Ii]ncorrect'))).to_be_visible(timeout=10000)"
|
||||||
|
]; }
|
||||||
|
{ username = "alice"; password = "AlicePassword"; nextPageExpect = [
|
||||||
|
"page.get_by_role('button', name=re.compile('Accept')).click()"
|
||||||
|
"expect(page.get_by_text(re.compile('[Ii]ncorrect'))).not_to_be_visible(timeout=10000)"
|
||||||
|
"expect(page.get_by_role('button', name=re.compile('Sign In'))).not_to_be_visible()"
|
||||||
|
"expect(page.get_by_text('new item')).to_be_visible()"
|
||||||
|
]; }
|
||||||
|
{ username = "bob"; password = "NotBobPassword"; nextPageExpect = [
|
||||||
|
"expect(page.get_by_text(re.compile('[Ii]ncorrect'))).to_be_visible(timeout=10000)"
|
||||||
|
]; }
|
||||||
|
{ username = "bob"; password = "BobPassword"; nextPageExpect = [
|
||||||
|
"page.get_by_role('button', name=re.compile('Accept')).click()"
|
||||||
|
"expect(page.get_by_text(re.compile('[Ii]ncorrect'))).not_to_be_visible(timeout=10000)"
|
||||||
|
"expect(page.get_by_role('button', name=re.compile('Sign In'))).not_to_be_visible()"
|
||||||
|
"expect(page.get_by_text('new item')).to_be_visible()"
|
||||||
|
]; }
|
||||||
|
{ username = "charlie"; password = "NotCharliePassword"; nextPageExpect = [
|
||||||
|
"expect(page.get_by_text(re.compile('[Ii]ncorrect'))).to_be_visible(timeout=10000)"
|
||||||
|
]; }
|
||||||
|
{ username = "charlie"; password = "CharliePassword"; nextPageExpect = [
|
||||||
|
# "page.get_by_role('button', name=re.compile('Accept')).click()" # I don't understand why this is not needed. Maybe it keeps somewhere the previous token?
|
||||||
|
"expect(page.get_by_text(re.compile('login failed'))).to_be_visible(timeout=10000)"
|
||||||
|
]; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sso = { config, ... }: {
|
||||||
|
shb.karakeep = {
|
||||||
|
sso = {
|
||||||
|
enable = true;
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
clientID = "karakeep";
|
||||||
|
|
||||||
|
nextauthSecret.result = config.shb.hardcodedsecret.nextauthSecret.result;
|
||||||
|
sharedSecret.result = config.shb.hardcodedsecret.oidcSecret.result;
|
||||||
|
sharedSecretForAuthelia.result = config.shb.hardcodedsecret.oidcAutheliaSecret.result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.hardcodedsecret.nextauthSecret = {
|
||||||
|
request = config.shb.karakeep.sso.nextauthSecret.request;
|
||||||
|
settings.content = nextauthSecret;
|
||||||
|
};
|
||||||
|
shb.hardcodedsecret.oidcSecret = {
|
||||||
|
request = config.shb.karakeep.sso.sharedSecret.request;
|
||||||
|
settings.content = oidcSecret;
|
||||||
|
};
|
||||||
|
shb.hardcodedsecret.oidcAutheliaSecret = {
|
||||||
|
request = config.shb.karakeep.sso.sharedSecretForAuthelia.request;
|
||||||
|
settings.content = oidcSecret;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
basic = pkgs.testers.runNixOSTest {
|
||||||
|
name = "karakeep_basic";
|
||||||
|
|
||||||
|
nodes.client = {};
|
||||||
|
nodes.server = {
|
||||||
|
imports = [
|
||||||
|
basic
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = commonTestScript.access;
|
||||||
|
};
|
||||||
|
|
||||||
|
backup = pkgs.testers.runNixOSTest {
|
||||||
|
name = "karakeep_backup";
|
||||||
|
|
||||||
|
nodes.server = { config, ... }: {
|
||||||
|
imports = [
|
||||||
|
basic
|
||||||
|
(testLib.backup config.shb.karakeep.backup)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes.client = {};
|
||||||
|
|
||||||
|
testScript = commonTestScript.backup;
|
||||||
|
};
|
||||||
|
|
||||||
|
https = pkgs.testers.runNixOSTest {
|
||||||
|
name = "karakeep_https";
|
||||||
|
|
||||||
|
nodes.client = {};
|
||||||
|
nodes.server = {
|
||||||
|
imports = [
|
||||||
|
basic
|
||||||
|
testLib.certs
|
||||||
|
https
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = commonTestScript.access;
|
||||||
|
};
|
||||||
|
|
||||||
|
sso = pkgs.testers.runNixOSTest {
|
||||||
|
name = "karakeep_sso";
|
||||||
|
interactive.sshBackdoor.enable = true;
|
||||||
|
|
||||||
|
nodes.client = {
|
||||||
|
imports = [
|
||||||
|
clientLoginSso
|
||||||
|
];
|
||||||
|
|
||||||
|
virtualisation.memorySize = 4096;
|
||||||
|
};
|
||||||
|
nodes.server = { config, pkgs, ... }: {
|
||||||
|
imports = [
|
||||||
|
basic
|
||||||
|
testLib.certs
|
||||||
|
https
|
||||||
|
testLib.ldap
|
||||||
|
ldap
|
||||||
|
(testLib.sso config.shb.certs.certs.selfsigned.n)
|
||||||
|
sso
|
||||||
|
];
|
||||||
|
|
||||||
|
virtualisation.memorySize = 4096;
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = commonTestScript.access;
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue