Compare commits

..

No commits in common. "main" and "flake-update-2024-06-10" have entirely different histories.

78 changed files with 9760 additions and 1157 deletions

View File

@ -1,18 +1,7 @@
Copyright 2023 Clan contributers
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -4,10 +4,8 @@ This repository contains nixos modules and terraform code that powers clan.lol.
The website and git hosting is currently on [hetzner](https://www.hetzner.com/).
## Servers
- web01:
- Instance type:
[ex101](https://www.hetzner.com/de/dedicated-rootserver/ex101)
- Instance type: [ex101](https://www.hetzner.com/de/dedicated-rootserver/ex101)
- CPU: Intel Core i9-13900 (24 cores / 32 threads)
- RAM: 64GB DDR5
- Drives: 2 x 1.92 TB NVME
@ -28,7 +26,5 @@ $ ./tf.sh apply
## To add a new project to CI
1. Add the 'buildbot-clan' topic to the repository using the "Manage topics"
button below the project description
2. Go to https://buildbot.clan.lol/#/builders/2 and press "Update projects"
after you have logged in.
1. Add the 'buildbot-clan' topic to the repository using the "Manage topics" button below the project description
2. Go to https://buildbot.clan.lol/#/builders/2 and press "Update projects" after you have logged in.

View File

@ -1,14 +1,14 @@
{
perSystem =
{ inputs', pkgs, ... }:
{ inputs'
, pkgs
, lib
, ...
}:
let
convert2Tofu =
provider:
provider.override (prev: {
homepage = builtins.replaceStrings [ "registry.terraform.io/providers" ] [
"registry.opentofu.org"
] prev.homepage;
});
convert2Tofu = provider: provider.override (prev: {
homepage = builtins.replaceStrings [ "registry.terraform.io/providers" ] [ "registry.opentofu.org" ] prev.homepage;
});
in
{
devShells.default = pkgs.mkShellNoCC {
@ -18,18 +18,17 @@
inputs'.clan-core.packages.clan-cli
(pkgs.opentofu.withPlugins (
p:
builtins.map convert2Tofu [
p.hetznerdns
p.hcloud
p.null
p.external
p.local
]
))
(pkgs.opentofu.withPlugins (p: builtins.map convert2Tofu [
p.hetznerdns
p.hcloud
p.null
p.external
p.local
]))
];
inputsFrom = [
inputs'.clan-core.devShells.default
];
inputsFrom = [ inputs'.clan-core.devShells.default ];
};
};
}

View File

@ -1,21 +1,5 @@
{
"nodes": {
"blobs": {
"flake": false,
"locked": {
"lastModified": 1604995301,
"narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=",
"owner": "simple-nixos-mailserver",
"repo": "blobs",
"rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265",
"type": "gitlab"
},
"original": {
"owner": "simple-nixos-mailserver",
"repo": "blobs",
"type": "gitlab"
}
},
"buildbot-nix": {
"inputs": {
"flake-parts": [
@ -29,11 +13,11 @@
]
},
"locked": {
"lastModified": 1719712463,
"narHash": "sha256-O2f16m1wnJtl3OldhucFuZpcF/cQ/xwtF7YQqVIoq0c=",
"lastModified": 1717897980,
"narHash": "sha256-CR85YGXFUaskmVRLa3WbAnD9+PgYle0TGkQMnEshuHQ=",
"owner": "Mic92",
"repo": "buildbot-nix",
"rev": "8d972a1a7675ab7429c6378b0203dc9408995e74",
"rev": "0d88c6776110ecf6705e9bfe1b777e6be6277da2",
"type": "github"
},
"original": {
@ -59,11 +43,11 @@
]
},
"locked": {
"lastModified": 1719728739,
"narHash": "sha256-Gf46MC7uCK1YKlGfiYH3coAyAacoRsLRpu7ijW939mI=",
"rev": "0f95bfd279b12865382f0ffd3459086090217fa1",
"lastModified": 1717937354,
"narHash": "sha256-qms0yCxEPvF/Vz0K8g5sBvPJlfXkYEmZuNT+hL7KYIY=",
"rev": "1eaf6cec391232a0b1f655fb4bf28380b89f7799",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/clan-core/archive/0f95bfd279b12865382f0ffd3459086090217fa1.tar.gz"
"url": "https://git.clan.lol/api/v1/repos/clan/clan-core/archive/1eaf6cec391232a0b1f655fb4bf28380b89f7799.tar.gz"
},
"original": {
"type": "tarball",
@ -78,11 +62,11 @@
]
},
"locked": {
"lastModified": 1718846788,
"narHash": "sha256-9dtXYtEkmXoUJV+PGLqscqF7qTn4AIhAKpFWRFU2NYs=",
"lastModified": 1717177033,
"narHash": "sha256-G3CZJafCO8WDy3dyA2EhpUJEmzd5gMJ2IdItAg0Hijw=",
"owner": "nix-community",
"repo": "disko",
"rev": "e1174d991944a01eaaa04bc59c6281edca4c0e6e",
"rev": "0274af4c92531ebfba4a5bd493251a143bc51f3c",
"type": "github"
},
"original": {
@ -91,21 +75,6 @@
"type": "github"
}
},
"flake-compat": {
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
@ -113,11 +82,11 @@
]
},
"locked": {
"lastModified": 1719745305,
"narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
"lastModified": 1717285511,
"narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
"rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
"type": "github"
},
"original": {
@ -126,41 +95,51 @@
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"nixlib": {
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"lastModified": 1712450863,
"narHash": "sha256-K6IkdtMtq9xktmYPj0uaYc8NsIqHuaAoRBaMgu9Fvrw=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "3c62b6a12571c9a7f65ab037173ee153d539905f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixos-2311": {
"locked": {
"lastModified": 1717017538,
"narHash": "sha256-S5kltvDDfNQM3xx9XcvzKEOyN2qk8Sa+aSOLqZ+1Ujc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "64e468fd2652105710d86cd2ae3e65a5a6d58dec",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixos-generators": {
"inputs": {
"nixlib": [
"clan-core",
"nixpkgs"
],
"nixlib": "nixlib",
"nixpkgs": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1718025593,
"narHash": "sha256-WZ1gdKq/9u1Ns/oXuNsDm+W0salonVA0VY1amw8urJ4=",
"lastModified": 1716210724,
"narHash": "sha256-iqQa3omRcHGpWb1ds75jS9ruA5R39FTmAkeR3J+ve1w=",
"owner": "nix-community",
"repo": "nixos-generators",
"rev": "35c20ba421dfa5059e20e0ef2343c875372bdcf3",
"rev": "d14b286322c7f4f897ca4b1726ce38cb68596c94",
"type": "github"
},
"original": {
@ -171,20 +150,18 @@
},
"nixos-images": {
"inputs": {
"nixos-stable": [
"clan-core"
],
"nixos-2311": "nixos-2311",
"nixos-unstable": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1718845599,
"narHash": "sha256-HbQ0iKohKJC5grC95HNjLxGPdgsc/BJgoENDYNbzkLo=",
"lastModified": 1717040312,
"narHash": "sha256-yI/en4IxuCEClIUpIs3QTyYCCtmSPLOhwLJclfNwdeg=",
"owner": "nix-community",
"repo": "nixos-images",
"rev": "c1e6a5f7b08f1c9993de1cfc5f15f838bf783b88",
"rev": "47bfb55316e105390dd761e0b6e8e0be09462b67",
"type": "github"
},
"original": {
@ -193,38 +170,13 @@
"type": "github"
}
},
"nixos-mailserver": {
"inputs": {
"blobs": "blobs",
"flake-compat": [
"flake-compat"
],
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-24_05": []
},
"locked": {
"lastModified": 1718697807,
"narHash": "sha256-Enla61WFisytTYbWygPynEbu8vozjeGc6Obkj2GRj7o=",
"owner": "simple-nixos-mailserver",
"repo": "nixos-mailserver",
"rev": "290a995de5c3d3f08468fa548f0d55ab2efc7b6b",
"type": "gitlab"
},
"original": {
"owner": "simple-nixos-mailserver",
"repo": "nixos-mailserver",
"type": "gitlab"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1719760900,
"narHash": "sha256-NkvFphHXKtQQ8F0XrqGlqkOhjHbE3671F8oLxwtTHhk=",
"lastModified": 1717868076,
"narHash": "sha256-c83Y9t815Wa34khrux81j8K8ET94ESmCuwORSKm2bQY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "12a9c0004bc987afb1ff511ebb97b67497a68e22",
"rev": "cd18e2ae9ab8e2a0a8d715b60c91b54c0ac35ff9",
"type": "github"
},
"original": {
@ -238,10 +190,7 @@
"inputs": {
"buildbot-nix": "buildbot-nix",
"clan-core": "clan-core",
"flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"flake-utils": "flake-utils",
"nixos-mailserver": "nixos-mailserver",
"nixpkgs": "nixpkgs",
"srvos": "srvos",
"treefmt-nix": "treefmt-nix"
@ -258,11 +207,11 @@
]
},
"locked": {
"lastModified": 1719111739,
"narHash": "sha256-kr2QzRrplzlCP87ddayCZQS+dhGW98kw2zy7+jUXtF4=",
"lastModified": 1717297459,
"narHash": "sha256-cZC2f68w5UrJ1f+2NWGV9Gx0dEYmxwomWN2B0lx0QRA=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "5e2e9421e9ed2b918be0a441c4535cfa45e04811",
"rev": "ab2a43b0d21d1d37d4d5726a892f714eaeb4b075",
"type": "github"
},
"original": {
@ -278,11 +227,11 @@
]
},
"locked": {
"lastModified": 1719753014,
"narHash": "sha256-Lfv5qtltKuO5+HNqOKZPlEuEZo7WaLiZjAI+sTqpwws=",
"lastModified": 1717807544,
"narHash": "sha256-djHfn29HdlfWdmyeu3rqlVS8k5q/xRh2P0mX2RAafb0=",
"owner": "numtide",
"repo": "srvos",
"rev": "22155bc76855f28a681b1d6987ea2420b899ad7e",
"rev": "64ae31cb29923128f27a503a550ee4fb1631c4c6",
"type": "github"
},
"original": {
@ -291,21 +240,6 @@
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
@ -313,16 +247,15 @@
]
},
"locked": {
"lastModified": 1719836491,
"narHash": "sha256-0kZeCwwYe51lN/9X2eCcBaAxFHeHTN1ieyuq/4UG8xg=",
"lastModified": 1717850719,
"narHash": "sha256-npYqVg+Wk4oxnWrnVG7416fpfrlRhp/lQ6wQ4DHI8YE=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "e78a4ce2041d5179f84b9a91001d9d35e72d3d21",
"rev": "4fc1c45a5f50169f9f29f6a98a438fb910b834ed",
"type": "github"
},
"original": {
"owner": "numtide",
"ref": "opentofu",
"repo": "treefmt-nix",
"type": "github"
}

115
flake.nix
View File

@ -8,20 +8,12 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
flake-compat.url = "github:edolstra/flake-compat";
flake-parts.url = "github:hercules-ci/flake-parts";
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
treefmt-nix.url = "github:numtide/treefmt-nix/opentofu";
treefmt-nix.url = "github:numtide/treefmt-nix";
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
nixos-mailserver = {
url = "gitlab:simple-nixos-mailserver/nixos-mailserver";
inputs.nixpkgs.follows = "nixpkgs";
inputs.nixpkgs-24_05.follows = "";
inputs.flake-compat.follows = "flake-compat";
};
srvos.url = "github:numtide/srvos";
# Use the version of nixpkgs that has been tested to work with SrvOS
srvos.inputs.nixpkgs.follows = "nixpkgs";
@ -37,72 +29,39 @@
buildbot-nix.inputs.treefmt-nix.follows = "treefmt-nix";
};
outputs =
inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } (
{ self, ... }:
{
systems = [
"x86_64-linux"
"aarch64-linux"
];
imports = [
inputs.treefmt-nix.flakeModule
./devShells/flake-module.nix
./targets/flake-module.nix
./modules/flake-module.nix
./pkgs/flake-module.nix
];
perSystem = (
{
lib,
self',
system,
pkgs,
...
}:
{
treefmt = {
package = pkgs.treefmt.overrideAttrs (_old: {
# https://github.com/numtide/treefmt/pull/325
patches = [ ./treefmt-config.patch ];
});
projectRootFile = ".git/config";
programs.terraform.enable = true;
programs.shellcheck.enable = true;
programs.deno.enable = true;
settings.global.excludes = [
# generated files
"sops/*"
"terraform.tfstate"
"*.tfvars.sops.json"
"*nixos-vars.json"
"secrets.yaml"
];
programs.nixfmt-rfc-style.enable = true;
settings.formatter.nixfmt-rfc-style.excludes = [
# generated files
"node-env.nix"
"node-packages.nix"
"composition.nix"
];
};
checks =
let
nixosMachines = lib.mapAttrs' (
name: config: lib.nameValuePair "nixos-${name}" config.config.system.build.toplevel
) ((lib.filterAttrs (_: config: config.pkgs.system == system)) self.nixosConfigurations);
packages = lib.mapAttrs' (n: lib.nameValuePair "package-${n}") self'.packages;
devShells = lib.mapAttrs' (n: lib.nameValuePair "devShell-${n}") self'.devShells;
homeConfigurations = lib.mapAttrs' (
name: config: lib.nameValuePair "home-manager-${name}" config.activation-script
) (self'.legacyPackages.homeConfigurations or { });
in
nixosMachines // packages // devShells // homeConfigurations;
}
);
}
);
outputs = inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } ({ self, ... }: {
systems = [
"x86_64-linux"
"aarch64-linux"
];
imports = [
inputs.treefmt-nix.flakeModule
./devShells/flake-module.nix
./targets/flake-module.nix
./modules/flake-module.nix
./pkgs/flake-module.nix
];
perSystem = ({ lib, self', system, ... }: {
treefmt = {
projectRootFile = ".git/config";
programs.hclfmt.enable = true;
programs.nixpkgs-fmt.enable = true;
settings.formatter.nixpkgs-fmt.excludes = [
# generated files
"node-env.nix"
"node-packages.nix"
"composition.nix"
];
};
checks =
let
nixosMachines = lib.mapAttrs' (name: config: lib.nameValuePair "nixos-${name}" config.config.system.build.toplevel) ((lib.filterAttrs (_: config: config.pkgs.system == system)) self.nixosConfigurations);
packages = lib.mapAttrs' (n: lib.nameValuePair "package-${n}") self'.packages;
devShells = lib.mapAttrs' (n: lib.nameValuePair "devShell-${n}") self'.devShells;
homeConfigurations = lib.mapAttrs' (name: config: lib.nameValuePair "home-manager-${name}" config.activation-script) (self'.legacyPackages.homeConfigurations or { });
in
nixosMachines // packages // devShells // homeConfigurations;
});
});
}

View File

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHS2PvT2e04pqbt1EFFN2y1za9nNmr8rcfnXq9kG5RS2 nixbld@turingmachine

View File

@ -41,10 +41,7 @@ in
extraGroups = [ "wheel" ];
shell = "/run/current-system/sw/bin/zsh";
uid = 1004;
openssh.authorizedKeys.keys = [
admins.kenji
admins.kenji-remote
];
openssh.authorizedKeys.keys = [ admins.kenji admins.kenji-remote ];
};
johannes = {
isNormalUser = true;

View File

@ -1,5 +1,4 @@
{ self, inputs, ... }:
{
{ self, inputs, ... }: {
flake.nixosModules = {
server.imports = [
inputs.srvos.nixosModules.server
@ -28,8 +27,6 @@
inputs.srvos.nixosModules.mixins-nginx
inputs.srvos.nixosModules.mixins-nix-experimental
./web01
inputs.nixos-mailserver.nixosModules.mailserver
./mailserver.nix
];
};
}

View File

@ -1,22 +1,31 @@
{ config, lib, ... }:
let
{ config
, lib
, ...
}:
with lib; let
cfg = config.clan.networking;
in
{
options = {
clan.networking.ipv4.address = lib.mkOption { type = lib.types.str; };
clan.networking.ipv4.address = mkOption {
type = types.str;
};
clan.networking.ipv4.cidr = lib.mkOption {
type = lib.types.str;
clan.networking.ipv4.cidr = mkOption {
type = types.str;
default = "26";
};
clan.networking.ipv4.gateway = lib.mkOption { type = lib.types.str; };
clan.networking.ipv4.gateway = mkOption {
type = types.str;
};
clan.networking.ipv6.address = lib.mkOption { type = lib.types.str; };
clan.networking.ipv6.address = mkOption {
type = types.str;
};
clan.networking.ipv6.cidr = lib.mkOption {
type = lib.types.str;
clan.networking.ipv6.cidr = mkOption {
type = types.str;
default = "64";
};
};

View File

@ -1,54 +0,0 @@
{ config, pkgs, ... }:
let
mailPassword =
{ service }:
{
secret."${service}-password" = { };
secret."${service}-password-hash" = { };
generator.path = with pkgs; [
coreutils
xkcdpass
mkpasswd
];
generator.script = ''
xkcdpass -n 4 -d - > $secrets/${service}-password
cat $secrets/${service}-password | mkpasswd -s -m bcrypt > $secrets/${service}-password-hash
'';
};
in
{
mailserver = {
enable = true;
fqdn = "mail.clan.lol";
domains = [ "clan.lol" ];
enablePop3 = true;
certificateScheme = "acme-nginx";
# kresd sucks unfortunally (fails when one NS server is not working, instead of trying other ones)
localDnsResolver = false;
loginAccounts."golem@clan.lol".hashedPasswordFile =
config.clan.core.facts.services.golem-mail.secret.golem-password-hash.path;
loginAccounts."gitea@clan.lol".hashedPasswordFile =
config.clan.core.facts.services.gitea-mail.secret.gitea-password-hash.path;
};
services.unbound = {
enable = true;
settings.server = {
prefetch = "yes";
prefetch-key = true;
qname-minimisation = true;
# Too many broken dnssec setups even at big companies such as amazon.
# Breaks my email setup. Better rely on tls for security.
val-permissive-mode = "yes";
};
};
# use local unbound as dns resolver
networking.nameservers = [ "127.0.0.1" ];
security.acme.acceptTerms = true;
clan.core.facts.services.golem-mail = mailPassword { service = "golem"; };
clan.core.facts.services.gitea-mail = mailPassword { service = "gitea"; };
}

View File

@ -1,21 +1,26 @@
{ config, self, ... }:
{
imports = [ self.inputs.clan-core.clanModules.borgbackup ];
{ config, ... }: {
# 100GB storagebox is under the nix-community hetzner account
clan.borgbackup.destinations.${config.networking.hostName} = {
repo = "u366395@u366395.your-storagebox.de:/./borgbackup";
rsh = "ssh -oPort=23 -i ${config.clan.core.facts.services.borgbackup.secret."borgbackup.ssh".path}";
};
clan.core.state.system.folders = [
"/home"
"/etc"
"/var"
"/root"
systemd.services.borgbackup-job-clan-lol.serviceConfig.ReadWritePaths = [
"/var/log/telegraf"
];
services.borgbackup.jobs.${config.networking.hostName} = {
# Run this from the hetzner network:
# ssh-keyscan -p 23 u359378.your-storagebox.de
programs.ssh.knownHosts = {
storagebox-ecdsa.hostNames = [ "[u359378.your-storagebox.de]:23" ];
storagebox-ecdsa.publicKey = "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAGK0po6usux4Qv2d8zKZN1dDvbWjxKkGsx7XwFdSUCnF19Q8psHEUWR7C/LtSQ5crU/g+tQVRBtSgoUcE8T+FWp5wBxKvWG2X9gD+s9/4zRmDeSJR77W6gSA/+hpOZoSE+4KgNdnbYSNtbZH/dN74EG7GLb/gcIpbUUzPNXpfKl7mQitw==";
storagebox-rsa.hostNames = [ "[u359378.your-storagebox.de]:23" ];
storagebox-rsa.publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA5EB5p/5Hp3hGW1oHok+PIOH9Pbn7cnUiGmUEBrCVjnAw+HrKyN8bYVV0dIGllswYXwkG/+bgiBlE6IVIBAq+JwVWu1Sss3KarHY3OvFJUXZoZyRRg/Gc/+LRCE7lyKpwWQ70dbelGRyyJFH36eNv6ySXoUYtGkwlU5IVaHPApOxe4LHPZa/qhSRbPo2hwoh0orCtgejRebNtW5nlx00DNFgsvn8Svz2cIYLxsPVzKgUxs8Zxsxgn+Q/UvR7uq4AbAhyBMLxv7DjJ1pc7PJocuTno2Rw9uMZi1gkjbnmiOh6TTXIEWbnroyIhwc8555uto9melEUmWNQ+C+PwAK+MPw==";
};
services.borgbackup.jobs.clan-lol = {
paths = [
"/home"
"/var"
"/root"
];
exclude = [
"*.pyc"
"/home/*/.direnv"
@ -36,20 +41,32 @@
"/var/tmp"
"/var/log"
];
# $ ssh-keygen -y -f /run/secrets/hetzner-borgbackup-ssh > /tmp/hetzner-borgbackup-ssh.pub
# $ cat /tmp/hetzner-borgbackup-ssh.pub | ssh -p23 u366395@u366395.your-storagebox.de install-ssh-key
repo = "u366395@u366395.your-storagebox.de:/./borgbackup";
# Disaster recovery:
# get the backup passphrase and ssh key from the sops and store them in /tmp
# $ export BORG_PASSCOMMAND='cat /tmp/hetzner-borgbackup-passphrase'
# $ export BORG_REPO='u359378@u359378.your-storagebox.de:/./borgbackup'
# $ export BORG_RSH='ssh -oPort=23 -i /tmp/hetzner-borgbackup-ssh'
# $ export BORG_RSH='ssh -oPort=23 -i /tmp/hetzner-borgbackup-ssh'
# $ borg list
# web01-clan-lol-2023-07-21T14:12:22 Fri, 2023-07-21 14:12:27 [539b1037669ffd0d3f50020f439bbe2881b7234910e405eafc333125383351bc]
# $ borg mount u359378@u359378.your-storagebox.de:/./borgbackup::web01-clan-lol-2023-07-21T14:12:22 /tmp/backup
doInit = true;
encryption = {
mode = "repokey-blake2";
# $ nix run nixpkgs#xkcdpass -- -d '-' -n 3 -C capitalize "$@"
passCommand = "cat ${config.sops.secrets.hetzner-borgbackup-passphrase.path}";
};
compression = "auto,zstd";
startAt = "daily";
# Also enable ssh support in the storagebox web interface.
# By default the storage box is only accessible from the hetzner network.
# $ clan facts generate
# $ clan facts list web01 | jq .borgbackup.ssh.pub | ssh -p23 u359378@u359378.your-storagebox.de install-ssh-key
# $ ssh-keygen -t ed25519 -N "" -f /tmp/ssh_host_ed25519_key
# $ cat /tmp/ssh_host_ed25519_key.pub | ssh -p23 u359378@u359378.your-storagebox.de install-ssh-key
environment.BORG_RSH = "ssh -oPort=23 -i ${config.sops.secrets.hetzner-borgbackup-ssh.path}";
preHook = ''
set -x
'';
@ -59,19 +76,12 @@
task,frequency=daily last_run=$(date +%s)i,state="$([[ $exitStatus == 0 ]] && echo ok || echo fail)"
EOF
'';
};
systemd.services."borgbackup-job-${config.networking.hostName}".serviceConfig.ReadWritePaths = [
"/var/log/telegraf"
];
# Run this from the hetzner network:
# ssh-keyscan -p 23 u359378.your-storagebox.de
programs.ssh.knownHosts = {
storagebox-ecdsa.hostNames = [ "[u359378.your-storagebox.de]:23" ];
storagebox-ecdsa.publicKey = "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAGK0po6usux4Qv2d8zKZN1dDvbWjxKkGsx7XwFdSUCnF19Q8psHEUWR7C/LtSQ5crU/g+tQVRBtSgoUcE8T+FWp5wBxKvWG2X9gD+s9/4zRmDeSJR77W6gSA/+hpOZoSE+4KgNdnbYSNtbZH/dN74EG7GLb/gcIpbUUzPNXpfKl7mQitw==";
storagebox-rsa.hostNames = [ "[u359378.your-storagebox.de]:23" ];
storagebox-rsa.publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA5EB5p/5Hp3hGW1oHok+PIOH9Pbn7cnUiGmUEBrCVjnAw+HrKyN8bYVV0dIGllswYXwkG/+bgiBlE6IVIBAq+JwVWu1Sss3KarHY3OvFJUXZoZyRRg/Gc/+LRCE7lyKpwWQ70dbelGRyyJFH36eNv6ySXoUYtGkwlU5IVaHPApOxe4LHPZa/qhSRbPo2hwoh0orCtgejRebNtW5nlx00DNFgsvn8Svz2cIYLxsPVzKgUxs8Zxsxgn+Q/UvR7uq4AbAhyBMLxv7DjJ1pc7PJocuTno2Rw9uMZi1gkjbnmiOh6TTXIEWbnroyIhwc8555uto9melEUmWNQ+C+PwAK+MPw==";
prune.keep = {
within = "1d"; # Keep all archives from the last day
daily = 7;
weekly = 4;
monthly = 0;
};
};
}

View File

@ -1,18 +1,10 @@
{
config,
self,
pkgs,
...
}:
{
{ config, self, pkgs, ... }: {
# service to for automatic merge bot
systemd.services.clan-merge = {
description = "Merge clan.lol PRs automatically";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment = {
GITEA_TOKEN_FILE = "%d/GITEA_TOKEN_FILE";
};
environment = { GITEA_TOKEN_FILE = "%d/GITEA_TOKEN_FILE"; };
serviceConfig = {
LoadCredential = [ "GITEA_TOKEN_FILE:${config.sops.secrets.merge-bot-gitea-token.path}" ];
Restart = "on-failure";

View File

@ -1,5 +1,4 @@
{ self, ... }:
{
{ self, ... }: {
imports = [
./borgbackup.nix
./clan-merge.nix
@ -9,7 +8,7 @@
./homepage.nix
./postfix.nix
./jobs.nix
./matrix-synapse.nix
#./matrix-synapse.nix
../dev.nix
self.inputs.clan-core.clanModules.zt-tcp-relay
];

View File

@ -1,26 +1,8 @@
{
config,
self,
pkgs,
lib,
...
}:
{ config, self, pkgs, lib, ... }:
let
storeDeps = pkgs.runCommand "store-deps" { } ''
mkdir -p $out/bin
for dir in ${
toString [
pkgs.coreutils
pkgs.findutils
pkgs.gnugrep
pkgs.gawk
pkgs.git
pkgs.nix
pkgs.bash
pkgs.jq
pkgs.nodejs
]
}; do
for dir in ${toString [ pkgs.coreutils pkgs.findutils pkgs.gnugrep pkgs.gawk pkgs.git pkgs.nix pkgs.bash pkgs.jq pkgs.nodejs ]}; do
for bin in "$dir"/bin/*; do
ln -s "$bin" "$out/bin/$(basename "$bin")"
done
@ -32,95 +14,87 @@ let
'';
numInstances = 2;
in
lib.mkMerge [
lib.mkMerge [{
# everything here has no dependencies on the store
systemd.services.gitea-runner-nix-image = {
wantedBy = [ "multi-user.target" ];
after = [ "podman.service" ];
requires = [ "podman.service" ];
path = [ config.virtualisation.podman.package pkgs.gnutar pkgs.shadow pkgs.getent ];
# we also include etc here because the cleanup job also wants the nixuser to be present
script = ''
set -eux -o pipefail
mkdir -p etc/nix
# Create an unpriveleged user that we can use also without the run-as-user.sh script
touch etc/passwd etc/group
groupid=$(cut -d: -f3 < <(getent group nixuser))
userid=$(cut -d: -f3 < <(getent passwd nixuser))
groupadd --prefix $(pwd) --gid "$groupid" nixuser
emptypassword='$6$1ero.LwbisiU.h3D$GGmnmECbPotJoPQ5eoSTD6tTjKnSWZcjHoVTkxFLZP17W9hRi/XkmCiAMOfWruUwy8gMjINrBMNODc7cYEo4K.'
useradd --prefix $(pwd) -p "$emptypassword" -m -d /tmp -u "$userid" -g "$groupid" -G nixuser nixuser
cat <<NIX_CONFIG > etc/nix/nix.conf
accept-flake-config = true
experimental-features = nix-command flakes
NIX_CONFIG
cat <<NSSWITCH > etc/nsswitch.conf
passwd: files mymachines systemd
group: files mymachines systemd
shadow: files
hosts: files mymachines dns myhostname
networks: files
ethers: files
services: files
protocols: files
rpc: files
NSSWITCH
# list the content as it will be imported into the container
tar -cv . | tar -tvf -
tar -cv . | podman import - gitea-runner-nix
'';
serviceConfig = {
RuntimeDirectory = "gitea-runner-nix-image";
WorkingDirectory = "/run/gitea-runner-nix-image";
Type = "oneshot";
RemainAfterExit = true;
};
};
users.users.nixuser = {
group = "nixuser";
description = "Used for running nix ci jobs";
home = "/var/empty";
isSystemUser = true;
};
users.groups.nixuser = { };
}
{
# everything here has no dependencies on the store
systemd.services.gitea-runner-nix-image = {
systemd.services = lib.genAttrs (builtins.genList (n: "gitea-runner-nix${builtins.toString n}-token") numInstances) (name: {
wantedBy = [ "multi-user.target" ];
after = [ "podman.service" ];
requires = [ "podman.service" ];
path = [
config.virtualisation.podman.package
pkgs.gnutar
pkgs.shadow
pkgs.getent
];
# we also include etc here because the cleanup job also wants the nixuser to be present
after = [ "gitea.service" ];
environment = {
GITEA_CUSTOM = "/var/lib/gitea/custom";
GITEA_WORK_DIR = "/var/lib/gitea";
};
script = ''
set -eux -o pipefail
mkdir -p etc/nix
# Create an unpriveleged user that we can use also without the run-as-user.sh script
touch etc/passwd etc/group
groupid=$(cut -d: -f3 < <(getent group nixuser))
userid=$(cut -d: -f3 < <(getent passwd nixuser))
groupadd --prefix $(pwd) --gid "$groupid" nixuser
emptypassword='$6$1ero.LwbisiU.h3D$GGmnmECbPotJoPQ5eoSTD6tTjKnSWZcjHoVTkxFLZP17W9hRi/XkmCiAMOfWruUwy8gMjINrBMNODc7cYEo4K.'
useradd --prefix $(pwd) -p "$emptypassword" -m -d /tmp -u "$userid" -g "$groupid" -G nixuser nixuser
cat <<NIX_CONFIG > etc/nix/nix.conf
accept-flake-config = true
experimental-features = nix-command flakes
NIX_CONFIG
cat <<NSSWITCH > etc/nsswitch.conf
passwd: files mymachines systemd
group: files mymachines systemd
shadow: files
hosts: files mymachines dns myhostname
networks: files
ethers: files
services: files
protocols: files
rpc: files
NSSWITCH
# list the content as it will be imported into the container
tar -cv . | tar -tvf -
tar -cv . | podman import - gitea-runner-nix
set -euo pipefail
token=$(${lib.getExe self.packages.${pkgs.hostPlatform.system}.gitea} actions generate-runner-token)
echo "TOKEN=$token" > /var/lib/gitea-registration/${name}
'';
unitConfig.ConditionPathExists = [ "!/var/lib/gitea-registration/${name}" ];
serviceConfig = {
RuntimeDirectory = "gitea-runner-nix-image";
WorkingDirectory = "/run/gitea-runner-nix-image";
User = "gitea";
Group = "gitea";
StateDirectory = "gitea-registration";
Type = "oneshot";
RemainAfterExit = true;
};
};
users.users.nixuser = {
group = "nixuser";
description = "Used for running nix ci jobs";
home = "/var/empty";
isSystemUser = true;
};
users.groups.nixuser = { };
}
{
systemd.services =
lib.genAttrs (builtins.genList (n: "gitea-runner-nix${builtins.toString n}-token") numInstances)
(name: {
wantedBy = [ "multi-user.target" ];
after = [ "gitea.service" ];
environment = {
GITEA_CUSTOM = "/var/lib/gitea/custom";
GITEA_WORK_DIR = "/var/lib/gitea";
};
script = ''
set -euo pipefail
token=$(${lib.getExe self.packages.${pkgs.hostPlatform.system}.gitea} actions generate-runner-token)
echo "TOKEN=$token" > /var/lib/gitea-registration/${name}
'';
unitConfig.ConditionPathExists = [ "!/var/lib/gitea-registration/${name}" ];
serviceConfig = {
User = "gitea";
Group = "gitea";
StateDirectory = "gitea-registration";
Type = "oneshot";
RemainAfterExit = true;
};
});
});
# Format of the token file:
virtualisation = {
@ -137,119 +111,106 @@ lib.mkMerge [
virtualisation.containers.containersConf.settings = {
# podman seems to not work with systemd-resolved
containers.dns_servers = [
"8.8.8.8"
"8.8.4.4"
];
containers.dns_servers = [ "8.8.8.8" "8.8.4.4" ];
};
}
{
systemd.services =
lib.genAttrs (builtins.genList (n: "gitea-runner-nix${builtins.toString n}") numInstances)
(name: {
after = [
"${name}-token.service"
"gitea-runner-nix-image.service"
];
requires = [
"${name}-token.service"
"gitea-runner-nix-image.service"
];
systemd.services = lib.genAttrs (builtins.genList (n: "gitea-runner-nix${builtins.toString n}") numInstances) (name: {
after = [
"${name}-token.service"
"gitea-runner-nix-image.service"
];
requires = [
"${name}-token.service"
"gitea-runner-nix-image.service"
];
# TODO: systemd confinment
serviceConfig = {
# Hardening (may overlap with DynamicUser=)
# The following options are only for optimizing output of systemd-analyze
AmbientCapabilities = "";
CapabilityBoundingSet = "";
# ProtectClock= adds DeviceAllow=char-rtc r
DeviceAllow = "";
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectSystem = "strict";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
UMask = "0066";
ProtectProc = "invisible";
SystemCallFilter = [
"~@clock"
"~@cpu-emulation"
"~@module"
"~@mount"
"~@obsolete"
"~@raw-io"
"~@reboot"
"~@swap"
# needed by go?
#"~@resources"
"~@privileged"
"~capset"
"~setdomainname"
"~sethostname"
];
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
"AF_NETLINK"
];
# TODO: systemd confinment
serviceConfig = {
# Hardening (may overlap with DynamicUser=)
# The following options are only for optimizing output of systemd-analyze
AmbientCapabilities = "";
CapabilityBoundingSet = "";
# ProtectClock= adds DeviceAllow=char-rtc r
DeviceAllow = "";
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectSystem = "strict";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
UMask = "0066";
ProtectProc = "invisible";
SystemCallFilter = [
"~@clock"
"~@cpu-emulation"
"~@module"
"~@mount"
"~@obsolete"
"~@raw-io"
"~@reboot"
"~@swap"
# needed by go?
#"~@resources"
"~@privileged"
"~capset"
"~setdomainname"
"~sethostname"
];
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" "AF_NETLINK" ];
# Needs network access
PrivateNetwork = false;
# Cannot be true due to Node
MemoryDenyWriteExecute = false;
# Needs network access
PrivateNetwork = false;
# Cannot be true due to Node
MemoryDenyWriteExecute = false;
# The more restrictive "pid" option makes `nix` commands in CI emit
# "GC Warning: Couldn't read /proc/stat"
# You may want to set this to "pid" if not using `nix` commands
ProcSubset = "all";
# Coverage programs for compiled code such as `cargo-tarpaulin` disable
# ASLR (address space layout randomization) which requires the
# `personality` syscall
# You may want to set this to `true` if not using coverage tooling on
# compiled code
LockPersonality = false;
# The more restrictive "pid" option makes `nix` commands in CI emit
# "GC Warning: Couldn't read /proc/stat"
# You may want to set this to "pid" if not using `nix` commands
ProcSubset = "all";
# Coverage programs for compiled code such as `cargo-tarpaulin` disable
# ASLR (address space layout randomization) which requires the
# `personality` syscall
# You may want to set this to `true` if not using coverage tooling on
# compiled code
LockPersonality = false;
# Note that this has some interactions with the User setting; so you may
# want to consult the systemd docs if using both.
DynamicUser = true;
};
});
# Note that this has some interactions with the User setting; so you may
# want to consult the systemd docs if using both.
DynamicUser = true;
};
});
services.gitea-actions-runner.instances =
lib.genAttrs (builtins.genList (n: "nix${builtins.toString n}") numInstances)
(name: {
enable = true;
name = "nix-runner";
# take the git root url from the gitea config
# only possible if you've also configured your gitea though the same nix config
# otherwise you need to set it manually
url = config.services.gitea.settings.server.ROOT_URL;
# use your favourite nix secret manager to get a path for this
tokenFile = "/var/lib/gitea-registration/gitea-runner-${name}-token";
labels = [ "nix:docker://gitea-runner-nix" ];
settings = {
container.options = "-e NIX_BUILD_SHELL=/bin/bash -e PAGER=cat -e PATH=/bin -e SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt --device /dev/kvm -v /nix:/nix -v ${storeDeps}/bin:/bin -v ${storeDeps}/etc/ssl:/etc/ssl --user nixuser --device=/dev/kvm";
# the default network that also respects our dns server settings
container.network = "host";
container.valid_volumes = [
"/nix"
"${storeDeps}/bin"
"${storeDeps}/etc/ssl"
];
};
});
}
]
services.gitea-actions-runner.instances = lib.genAttrs (builtins.genList (n: "nix${builtins.toString n}") numInstances) (name: {
enable = true;
name = "nix-runner";
# take the git root url from the gitea config
# only possible if you've also configured your gitea though the same nix config
# otherwise you need to set it manually
url = config.services.gitea.settings.server.ROOT_URL;
# use your favourite nix secret manager to get a path for this
tokenFile = "/var/lib/gitea-registration/gitea-runner-${name}-token";
labels = [ "nix:docker://gitea-runner-nix" ];
settings = {
container.options = "-e NIX_BUILD_SHELL=/bin/bash -e PAGER=cat -e PATH=/bin -e SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt --device /dev/kvm -v /nix:/nix -v ${storeDeps}/bin:/bin -v ${storeDeps}/etc/ssl:/etc/ssl --user nixuser --device=/dev/kvm";
# the default network that also respects our dns server settings
container.network = "host";
container.valid_volumes = [
"/nix"
"${storeDeps}/bin"
"${storeDeps}/etc/ssl"
];
};
});
}]

View File

@ -1,22 +1,12 @@
{
pkgs,
lib,
self,
config,
...
}:
{ config, pkgs, lib, self, ... }:
let
# make the logs for this host "public" so that they show up in e.g. metrics
publog =
vhost:
lib.attrsets.unionOfDisjoint vhost {
extraConfig =
(vhost.extraConfig or "")
+ ''
access_log /var/log/nginx/public.log vcombined;
'';
};
publog = vhost: lib.attrsets.unionOfDisjoint vhost {
extraConfig = (vhost.extraConfig or "") + ''
access_log /var/log/nginx/public.log vcombined;
'';
};
in
{
@ -37,17 +27,13 @@ in
package = self.packages.${pkgs.hostPlatform.system}.gitea;
settings.actions.ENABLED = true;
mailerPasswordFile = config.clan.core.facts.services.gitea-mail.secret.gitea-password.path;
settings.mailer = {
ENABLED = true;
FROM = "gitea@clan.lol";
USER = "gitea@clan.lol";
SMTP_ADDR = "mail.clan.lol";
SMTP_PORT = "587";
SMTP_ADDR = "localhost";
SMTP_PORT = 25;
PROTOCOL = "smtps";
};
settings.log.LEVEL = "Error";
settings.service.DISABLE_REGISTRATION = false;
settings.metrics.ENABLED = true;
@ -63,8 +49,6 @@ in
settings.session.COOKIE_SECURE = true;
};
sops.secrets.web01-gitea-password.owner = config.systemd.services.gitea.serviceConfig.User;
services.nginx.virtualHosts."git.clan.lol" = publog {
forceSSL = true;
enableACME = true;

View File

@ -1,5 +1,4 @@
{ pkgs, ... }:
{
{ pkgs, ... }: {
services.postgresql.enable = true;
services.postgresql.package = pkgs.postgresql_14;
services.postgresql.settings = {

View File

@ -1,4 +1,4 @@
{ pkgs, ... }:
{ stdenv, lib, pkgs, ... }:
let
domain = "metrics.clan.lol";
@ -38,13 +38,14 @@ in
"d ${pub_goaccess} 0755 goaccess nginx -"
];
# --browsers-file=/etc/goaccess/browsers.list
# https://raw.githubusercontent.com/allinurl/goaccess/master/config/browsers.list
systemd.services.goaccess = {
description = "GoAccess server monitoring";
preStart = ''
rm -f ${pub_goaccess}/index.html
'';
rm -f ${pub_goaccess}/index.html
'';
serviceConfig = {
User = "goaccess";
Group = "nginx";
@ -82,11 +83,7 @@ in
ProtectSystem = "strict";
SystemCallFilter = "~@clock @cpu-emulation @debug @keyring @memlock @module @mount @obsolete @privileged @reboot @resources @setuid @swap @raw-io";
ReadOnlyPaths = "/";
ReadWritePaths = [
"/proc/self"
"${pub_goaccess}"
"${priv_goaccess}"
];
ReadWritePaths = [ "/proc/self" "${pub_goaccess}" "${priv_goaccess}" ];
PrivateDevices = "yes";
ProtectKernelModules = "yes";
ProtectKernelTunables = "yes";
@ -95,6 +92,7 @@ in
wantedBy = [ "multi-user.target" ];
};
services.nginx.virtualHosts."${domain}" = {
addSSL = true;
enableACME = true;

View File

@ -1,18 +1,17 @@
{ config, pkgs, ... }:
{
{ config, pkgs, ... }: {
services.harmonia.enable = true;
# $ nix-store --generate-binary-cache-key cache.yourdomain.tld-1 harmonia.secret harmonia.pub
services.harmonia.signKeyPath = config.sops.secrets.harmonia-secret.path;
services.nginx = {
package = pkgs.nginxStable.override { modules = [ pkgs.nginxModules.zstd ]; };
package = pkgs.nginxStable.override {
modules = [ pkgs.nginxModules.zstd ];
};
};
# trust our own cache
nix.settings.trusted-substituters = [ "https://cache.clan.lol" ];
nix.settings.trusted-public-keys = [
"cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28="
];
nix.settings.trusted-public-keys = [ "cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28=" ];
services.nginx.virtualHosts."cache.clan.lol" = {
forceSSL = true;

View File

@ -1,4 +1,4 @@
{ config, ... }:
{ config, lib, pkgs, self, ... }:
{
security.acme.defaults.email = "admins@clan.lol";
@ -6,11 +6,13 @@
# www user to push website artifacts via ssh
users.users.www = {
openssh.authorizedKeys.keys = config.users.users.root.openssh.authorizedKeys.keys ++ [
# ssh-homepage-key
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxZ3Av30M6Sh6NU1mnCskB16bYtNP8vskc/+ud0AU1C ssh-homepage-key"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBuYyfSuETSrwqCsWHeeClqjcsFlMEmiJN6Rr8/DwrU0 gitea-ci"
];
openssh.authorizedKeys.keys =
config.users.users.root.openssh.authorizedKeys.keys
++ [
# ssh-homepage-key
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxZ3Av30M6Sh6NU1mnCskB16bYtNP8vskc/+ud0AU1C ssh-homepage-key"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBuYyfSuETSrwqCsWHeeClqjcsFlMEmiJN6Rr8/DwrU0 gitea-ci"
];
isSystemUser = true;
shell = "/run/current-system/sw/bin/bash";
group = "www";
@ -18,7 +20,9 @@
users.groups.www = { };
# ensure /var/www can be accessed by nginx and www user
systemd.tmpfiles.rules = [ "d /var/www 0755 www nginx" ];
systemd.tmpfiles.rules = [
"d /var/www 0755 www nginx"
];
services.nginx = {

View File

@ -1,10 +1,4 @@
{
config,
self,
pkgs,
lib,
...
}:
{ config, self, pkgs, lib, ... }:
let
configForJob = name: {
systemd.timers.${name} = {
@ -52,11 +46,9 @@ let
};
in
{
config = lib.mkMerge (
map configForJob [
"job-flake-update-clan-core"
"job-flake-update-clan-homepage"
"job-flake-update-clan-infra"
]
);
config = lib.mkMerge (map configForJob [
"job-flake-update-clan-core"
"job-flake-update-clan-homepage"
"job-flake-update-clan-infra"
]);
}

View File

@ -1,30 +1,6 @@
{ self, ... }:
{
imports = [ self.inputs.clan-core.clanModules.matrix-synapse ];
clan.matrix-synapse.enable = true;
clan.matrix-synapse.domain = "clan.lol";
clan.matrix-synapse.users.admin = {
admin = true;
};
clan.matrix-synapse.users.monitoring = { };
clan.matrix-synapse.users.clan-bot = { };
# Rate limiting settings
# we need to up this to be able to support matrix bots
services.matrix-synapse.settings = {
rc_login = {
address = {
per_second = 20;
burst_count = 200;
};
account = {
per_second = 20;
burst_count = 200;
};
failed_attempts = {
per_second = 3;
burst_count = 15;
};
};
};
}

View File

@ -1,41 +1,40 @@
{ }
{ config, ... }:
#{ config, ... }:
#let
# domain = "clan.lol";
#in
#{
# services.opendkim.enable = true;
# services.opendkim.domains = domain;
# services.opendkim.selector = "v1";
# services.opendkim.user = config.services.postfix.user;
# services.opendkim.group = config.services.postfix.group;
#
# # postfix configuration for sending emails only
# services.postfix = {
# enable = true;
# hostname = "mail.${domain}";
# inherit domain;
#
# config = {
# smtp_tls_note_starttls_offer = "yes";
#
# smtp_dns_support_level = "dnssec";
# smtp_tls_security_level = "dane";
#
# tls_medium_cipherlist = "AES128+EECDH:AES128+EDH";
#
# smtpd_relay_restrictions = "permit_mynetworks permit_sasl_authenticated defer_unauth_destination";
# mydestination = "localhost.$mydomain, localhost, $myhostname";
# myorigin = "$mydomain";
#
# milter_default_action = "accept";
# milter_protocol = "6";
# smtpd_milters = "unix:/run/opendkim/opendkim.sock";
# non_smtpd_milters = "unix:/run/opendkim/opendkim.sock";
#
# inet_interfaces = "loopback-only";
# inet_protocols = "all";
# };
# };
#}
let
domain = "clan.lol";
in
{
services.opendkim.enable = true;
services.opendkim.domains = domain;
services.opendkim.selector = "v1";
services.opendkim.user = config.services.postfix.user;
services.opendkim.group = config.services.postfix.group;
# postfix configuration for sending emails only
services.postfix = {
enable = true;
hostname = "mail.${domain}";
inherit domain;
config = {
smtp_tls_note_starttls_offer = "yes";
smtp_dns_support_level = "dnssec";
smtp_tls_security_level = "dane";
tls_medium_cipherlist = "AES128+EECDH:AES128+EDH";
smtpd_relay_restrictions = "permit_mynetworks permit_sasl_authenticated defer_unauth_destination";
mydestination = "localhost.$mydomain, localhost, $myhostname";
myorigin = "$mydomain";
milter_default_action = "accept";
milter_protocol = "6";
smtpd_milters = "unix:/run/opendkim/opendkim.sock";
non_smtpd_milters = "unix:/run/opendkim/opendkim.sock";
inet_interfaces = "loopback-only";
inet_protocols = "all";
};
};
}

View File

@ -1,3 +1,4 @@
{ self, ... }:
let
mirrorBoot = idx: {
type = "disk";
@ -40,14 +41,8 @@ in
efiSupport = true;
efiInstallAsRemovable = true;
mirroredBoots = [
{
path = "/boot0";
devices = [ "nodev" ];
}
{
path = "/boot1";
devices = [ "nodev" ];
}
{ path = "/boot0"; devices = [ "nodev" ]; }
{ path = "/boot1"; devices = [ "nodev" ]; }
];
};

View File

@ -1,19 +1,10 @@
{
bash,
coreutils,
git,
tea,
openssh,
writePureShellScriptBin,
{ bash
, coreutils
, git
, tea
, openssh
, writePureShellScriptBin
}:
writePureShellScriptBin "action-create-pr"
[
bash
coreutils
git
tea
openssh
]
''
bash ${./script.sh} "$@"
''
writePureShellScriptBin "action-create-pr" [ bash coreutils git tea openssh ] ''
bash ${./script.sh} "$@"
''

View File

@ -1,15 +1,8 @@
{
bash,
coreutils,
tea,
writePureShellScriptBin,
{ bash
, coreutils
, tea
, writePureShellScriptBin
}:
writePureShellScriptBin "action-ensure-tea-login"
[
bash
coreutils
tea
]
''
bash ${./script.sh}
''
writePureShellScriptBin "action-ensure-tea-login" [ bash coreutils tea ] ''
bash ${./script.sh}
''

View File

@ -8,5 +8,5 @@ fi
GITEA_TOKEN="${GITEA_TOKEN:-"$(cat "$GITEA_TOKEN_FILE")"}"
tea login add \
--token "$GITEA_TOKEN" \
--url "$GITEA_URL"
--token $GITEA_TOKEN \
--url $GITEA_URL

View File

@ -1,23 +1,20 @@
{
bash,
coreutils,
git,
openssh,
action-ensure-tea-login,
action-create-pr,
action-flake-update,
writePureShellScriptBin,
{ bash
, coreutils
, git
, openssh
, action-ensure-tea-login
, action-create-pr
, action-flake-update
, writePureShellScriptBin
}:
writePureShellScriptBin "action-flake-update-pr-clan"
[
bash
coreutils
git
openssh
action-ensure-tea-login
action-create-pr
action-flake-update
]
''
bash ${./script.sh}
''
writePureShellScriptBin "action-flake-update-pr-clan" [
bash
coreutils
git
openssh
action-ensure-tea-login
action-create-pr
action-flake-update
] ''
bash ${./script.sh}
''

View File

@ -5,10 +5,8 @@ set -euo pipefail
export KEEP_VARS="GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GITEA_URL GITEA_USER PR_TITLE REMOTE_BRANCH REPO_DIR${KEEP_VARS:+ $KEEP_VARS}"
# configure variables for actions
today=$(date --iso-8601)
today_minutes=$(date --iso-8601=minutes)
export PR_TITLE="Automatic flake update - ${today_minutes}"
export REMOTE_BRANCH="flake-update-${today}"
export PR_TITLE="Automatic flake update - $(date --iso-8601=minutes)"
export REMOTE_BRANCH="flake-update-$(date --iso-8601)"
export REPO_DIR=$TMPDIR/repo
export GIT_AUTHOR_NAME="Clan Merge Bot"
export GIT_AUTHOR_EMAIL="clan-bot@git.clan.lol"

View File

@ -1,17 +1,9 @@
{
bash,
coreutils,
git,
nix,
writePureShellScriptBin,
{ bash
, coreutils
, git
, nix
, writePureShellScriptBin
}:
writePureShellScriptBin "action-flake-update"
[
bash
coreutils
git
nix
]
''
bash ${./script.sh}
''
writePureShellScriptBin "action-flake-update" [ bash coreutils git nix ] ''
bash ${./script.sh}
''

View File

@ -1,7 +1,7 @@
import argparse
import json
import urllib.error
import urllib.request
import urllib.error
from os import environ
from typing import Optional
@ -38,7 +38,6 @@ def is_ci_green(pr: dict) -> bool:
return False
return True
def is_org_member(user: str, token: str) -> bool:
url = "https://git.clan.lol/api/v1/orgs/clan/members/" + user + f"?token={token}"
try:
@ -51,6 +50,7 @@ def is_org_member(user: str, token: str) -> bool:
raise
def merge_allowed(pr: dict, bot_name: str, token: str) -> bool:
assignees = pr["assignees"] if pr["assignees"] else []
if (

View File

@ -1,9 +1,9 @@
{
pkgs ? import <nixpkgs> { },
lib ? pkgs.lib,
python3 ? pkgs.python3,
ruff ? pkgs.ruff,
runCommand ? pkgs.runCommand,
{ pkgs ? import <nixpkgs> { }
, lib ? pkgs.lib
, python3 ? pkgs.python3
, ruff ? pkgs.ruff
, runCommand ? pkgs.runCommand
,
}:
let
pyproject = builtins.fromTOML (builtins.readFile ./pyproject.toml);
@ -32,11 +32,13 @@ let
package = python3.pkgs.buildPythonPackage {
inherit name src;
format = "pyproject";
nativeBuildInputs = [ python3.pkgs.setuptools ];
propagatedBuildInputs = dependencies ++ [ ];
passthru.tests = {
inherit check;
};
nativeBuildInputs = [
python3.pkgs.setuptools
];
propagatedBuildInputs =
dependencies
++ [ ];
passthru.tests = { inherit check; };
passthru.devDependencies = devDependencies;
};

View File

@ -1,6 +1,5 @@
{
perSystem =
{ pkgs, ... }:
perSystem = { pkgs, ... }:
let
package = pkgs.callPackage ./default.nix { inherit pkgs; };
in

View File

@ -1,11 +1,16 @@
{
pkgs ? import <nixpkgs> { },
}:
{ pkgs ? import <nixpkgs> { } }:
let
inherit (pkgs) lib python3;
package = import ./default.nix { inherit lib pkgs python3; };
package = import ./default.nix {
inherit lib pkgs python3;
};
pythonWithDeps = python3.withPackages (
ps: package.propagatedBuildInputs ++ package.devDependencies ++ [ ps.pip ]
ps:
package.propagatedBuildInputs
++ package.devDependencies
++ [
ps.pip
]
);
checkScript = pkgs.writeScriptBin "check" ''
nix build -f . tests -L "$@"

View File

@ -112,6 +112,4 @@ def test_list_prs_to_merge(monkeypatch: pytest.MonkeyPatch) -> None:
assignees=[dict(login=bot_name)],
),
]
assert clan_merge.list_prs_to_merge(prs, bot_name=bot_name, gitea_token="test") == [
prs[0]
]
assert clan_merge.list_prs_to_merge(prs, bot_name=bot_name, gitea_token="test") == [prs[0]]

View File

@ -1,37 +1,33 @@
{
imports = [ ./clan-merge/flake-module.nix ];
perSystem =
{ pkgs, config, ... }:
{
packages =
let
writers = pkgs.callPackage ./writers.nix { };
in
{
gitea = pkgs.callPackage ./gitea { };
imports = [
./clan-merge/flake-module.nix
];
perSystem = { pkgs, config, ... }: {
packages =
let
writers = pkgs.callPackage ./writers.nix { };
in
{
inherit (pkgs.callPackage ./renovate { }) renovate;
gitea = pkgs.callPackage ./gitea { };
action-create-pr = pkgs.callPackage ./action-create-pr {
inherit (writers) writePureShellScriptBin;
};
action-ensure-tea-login = pkgs.callPackage ./action-ensure-tea-login {
inherit (writers) writePureShellScriptBin;
};
action-flake-update = pkgs.callPackage ./action-flake-update {
inherit (writers) writePureShellScriptBin;
};
action-flake-update-pr-clan = pkgs.callPackage ./action-flake-update-pr-clan {
inherit (writers) writePureShellScriptBin;
inherit (config.packages) action-ensure-tea-login action-create-pr action-flake-update;
};
inherit
(pkgs.callPackages ./job-flake-updates {
inherit (writers) writePureShellScriptBin;
inherit (config.packages) action-flake-update-pr-clan;
})
job-flake-update-clan-core
job-flake-update-clan-homepage
job-flake-update-clan-infra
;
action-create-pr = pkgs.callPackage ./action-create-pr {
inherit (writers) writePureShellScriptBin;
};
};
action-ensure-tea-login = pkgs.callPackage ./action-ensure-tea-login {
inherit (writers) writePureShellScriptBin;
};
action-flake-update = pkgs.callPackage ./action-flake-update {
inherit (writers) writePureShellScriptBin;
};
action-flake-update-pr-clan = pkgs.callPackage ./action-flake-update-pr-clan {
inherit (writers) writePureShellScriptBin;
inherit (config.packages) action-ensure-tea-login action-create-pr action-flake-update;
};
inherit (pkgs.callPackages ./job-flake-updates {
inherit (writers) writePureShellScriptBin;
inherit (config.packages) action-flake-update-pr-clan;
}) job-flake-update-clan-core job-flake-update-clan-homepage job-flake-update-clan-infra;
};
};
}

View File

@ -1,13 +1,13 @@
{ action-flake-update-pr-clan, writePureShellScriptBin }:
{ action-flake-update-pr-clan
, writePureShellScriptBin
}:
let
job-flake-update =
repo:
writePureShellScriptBin "job-flake-update-${repo}" [ action-flake-update-pr-clan ] ''
export REPO="gitea@git.clan.lol:clan/${repo}.git"
export KEEP_VARS="REPO''${KEEP_VARS:+ $KEEP_VARS}"
job-flake-update = repo: writePureShellScriptBin "job-flake-update-${repo}" [ action-flake-update-pr-clan ] ''
export REPO="gitea@git.clan.lol:clan/${repo}.git"
export KEEP_VARS="REPO''${KEEP_VARS:+ $KEEP_VARS}"
action-flake-update-pr-clan
'';
action-flake-update-pr-clan
'';
in
{
job-flake-update-clan-core = job-flake-update "clan-core";

View File

@ -0,0 +1,17 @@
# This file has been generated by node2nix 1.11.1. Do not edit!
{pkgs ? import <nixpkgs> {
inherit system;
}, system ? builtins.currentSystem, nodejs ? pkgs."nodejs_18"}:
let
nodeEnv = import ./node-env.nix {
inherit (pkgs) stdenv lib python2 runCommand writeTextFile writeShellScript;
inherit pkgs nodejs;
libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
};
in
import ./node-packages.nix {
inherit (pkgs) fetchurl nix-gitignore stdenv lib fetchgit;
inherit nodeEnv;
}

View File

@ -0,0 +1,8 @@
{ pkgs, system, nodejs-18_x, makeWrapper }:
let
nodePackages = import ./composition.nix {
inherit pkgs system;
nodejs = nodejs-18_x;
};
in
nodePackages

5
pkgs/renovate/generate.sh Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash -p nodePackages.node2nix
rm -f node-env.nix
node2nix -18 -i node-packages.json -o node-packages.nix -c composition.nix

689
pkgs/renovate/node-env.nix Normal file
View File

@ -0,0 +1,689 @@
# This file originates from node2nix
{lib, stdenv, nodejs, python2, pkgs, libtool, runCommand, writeTextFile, writeShellScript}:
let
# Workaround to cope with utillinux in Nixpkgs 20.09 and util-linux in Nixpkgs master
utillinux = if pkgs ? utillinux then pkgs.utillinux else pkgs.util-linux;
python = if nodejs ? python then nodejs.python else python2;
# Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise
tarWrapper = runCommand "tarWrapper" {} ''
mkdir -p $out/bin
cat > $out/bin/tar <<EOF
#! ${stdenv.shell} -e
$(type -p tar) "\$@" --warning=no-unknown-keyword --delay-directory-restore
EOF
chmod +x $out/bin/tar
'';
# Function that generates a TGZ file from a NPM project
buildNodeSourceDist =
{ name, version, src, ... }:
stdenv.mkDerivation {
name = "node-tarball-${name}-${version}";
inherit src;
buildInputs = [ nodejs ];
buildPhase = ''
export HOME=$TMPDIR
tgzFile=$(npm pack | tail -n 1) # Hooks to the pack command will add output (https://docs.npmjs.com/misc/scripts)
'';
installPhase = ''
mkdir -p $out/tarballs
mv $tgzFile $out/tarballs
mkdir -p $out/nix-support
echo "file source-dist $out/tarballs/$tgzFile" >> $out/nix-support/hydra-build-products
'';
};
# Common shell logic
installPackage = writeShellScript "install-package" ''
installPackage() {
local packageName=$1 src=$2
local strippedName
local DIR=$PWD
cd $TMPDIR
unpackFile $src
# Make the base dir in which the target dependency resides first
mkdir -p "$(dirname "$DIR/$packageName")"
if [ -f "$src" ]
then
# Figure out what directory has been unpacked
packageDir="$(find . -maxdepth 1 -type d | tail -1)"
# Restore write permissions to make building work
find "$packageDir" -type d -exec chmod u+x {} \;
chmod -R u+w "$packageDir"
# Move the extracted tarball into the output folder
mv "$packageDir" "$DIR/$packageName"
elif [ -d "$src" ]
then
# Get a stripped name (without hash) of the source directory.
# On old nixpkgs it's already set internally.
if [ -z "$strippedName" ]
then
strippedName="$(stripHash $src)"
fi
# Restore write permissions to make building work
chmod -R u+w "$strippedName"
# Move the extracted directory into the output folder
mv "$strippedName" "$DIR/$packageName"
fi
# Change to the package directory to install dependencies
cd "$DIR/$packageName"
}
'';
# Bundle the dependencies of the package
#
# Only include dependencies if they don't exist. They may also be bundled in the package.
includeDependencies = {dependencies}:
lib.optionalString (dependencies != []) (
''
mkdir -p node_modules
cd node_modules
''
+ (lib.concatMapStrings (dependency:
''
if [ ! -e "${dependency.packageName}" ]; then
${composePackage dependency}
fi
''
) dependencies)
+ ''
cd ..
''
);
# Recursively composes the dependencies of a package
composePackage = { name, packageName, src, dependencies ? [], ... }@args:
builtins.addErrorContext "while evaluating node package '${packageName}'" ''
installPackage "${packageName}" "${src}"
${includeDependencies { inherit dependencies; }}
cd ..
${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
'';
pinpointDependencies = {dependencies, production}:
let
pinpointDependenciesFromPackageJSON = writeTextFile {
name = "pinpointDependencies.js";
text = ''
var fs = require('fs');
var path = require('path');
function resolveDependencyVersion(location, name) {
if(location == process.env['NIX_STORE']) {
return null;
} else {
var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json");
if(fs.existsSync(dependencyPackageJSON)) {
var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON));
if(dependencyPackageObj.name == name) {
return dependencyPackageObj.version;
}
} else {
return resolveDependencyVersion(path.resolve(location, ".."), name);
}
}
}
function replaceDependencies(dependencies) {
if(typeof dependencies == "object" && dependencies !== null) {
for(var dependency in dependencies) {
var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency);
if(resolvedVersion === null) {
process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n");
} else {
dependencies[dependency] = resolvedVersion;
}
}
}
}
/* Read the package.json configuration */
var packageObj = JSON.parse(fs.readFileSync('./package.json'));
/* Pinpoint all dependencies */
replaceDependencies(packageObj.dependencies);
if(process.argv[2] == "development") {
replaceDependencies(packageObj.devDependencies);
}
else {
packageObj.devDependencies = {};
}
replaceDependencies(packageObj.optionalDependencies);
replaceDependencies(packageObj.peerDependencies);
/* Write the fixed package.json file */
fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2));
'';
};
in
''
node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"}
${lib.optionalString (dependencies != [])
''
if [ -d node_modules ]
then
cd node_modules
${lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies}
cd ..
fi
''}
'';
# Recursively traverses all dependencies of a package and pinpoints all
# dependencies in the package.json file to the versions that are actually
# being used.
pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args:
''
if [ -d "${packageName}" ]
then
cd "${packageName}"
${pinpointDependencies { inherit dependencies production; }}
cd ..
${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
fi
'';
# Extract the Node.js source code which is used to compile packages with
# native bindings
nodeSources = runCommand "node-sources" {} ''
tar --no-same-owner --no-same-permissions -xf ${nodejs.src}
mv node-* $out
'';
# Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty)
addIntegrityFieldsScript = writeTextFile {
name = "addintegrityfields.js";
text = ''
var fs = require('fs');
var path = require('path');
function augmentDependencies(baseDir, dependencies) {
for(var dependencyName in dependencies) {
var dependency = dependencies[dependencyName];
// Open package.json and augment metadata fields
var packageJSONDir = path.join(baseDir, "node_modules", dependencyName);
var packageJSONPath = path.join(packageJSONDir, "package.json");
if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored
console.log("Adding metadata fields to: "+packageJSONPath);
var packageObj = JSON.parse(fs.readFileSync(packageJSONPath));
if(dependency.integrity) {
packageObj["_integrity"] = dependency.integrity;
} else {
packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads.
}
if(dependency.resolved) {
packageObj["_resolved"] = dependency.resolved; // Adopt the resolved property if one has been provided
} else {
packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories.
}
if(dependency.from !== undefined) { // Adopt from property if one has been provided
packageObj["_from"] = dependency.from;
}
fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2));
}
// Augment transitive dependencies
if(dependency.dependencies !== undefined) {
augmentDependencies(packageJSONDir, dependency.dependencies);
}
}
}
if(fs.existsSync("./package-lock.json")) {
var packageLock = JSON.parse(fs.readFileSync("./package-lock.json"));
if(![1, 2].includes(packageLock.lockfileVersion)) {
process.stderr.write("Sorry, I only understand lock file versions 1 and 2!\n");
process.exit(1);
}
if(packageLock.dependencies !== undefined) {
augmentDependencies(".", packageLock.dependencies);
}
}
'';
};
# Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes
reconstructPackageLock = writeTextFile {
name = "reconstructpackagelock.js";
text = ''
var fs = require('fs');
var path = require('path');
var packageObj = JSON.parse(fs.readFileSync("package.json"));
var lockObj = {
name: packageObj.name,
version: packageObj.version,
lockfileVersion: 2,
requires: true,
packages: {
"": {
name: packageObj.name,
version: packageObj.version,
license: packageObj.license,
bin: packageObj.bin,
dependencies: packageObj.dependencies,
engines: packageObj.engines,
optionalDependencies: packageObj.optionalDependencies
}
},
dependencies: {}
};
function augmentPackageJSON(filePath, packages, dependencies) {
var packageJSON = path.join(filePath, "package.json");
if(fs.existsSync(packageJSON)) {
var packageObj = JSON.parse(fs.readFileSync(packageJSON));
packages[filePath] = {
version: packageObj.version,
integrity: "sha1-000000000000000000000000000=",
dependencies: packageObj.dependencies,
engines: packageObj.engines,
optionalDependencies: packageObj.optionalDependencies
};
dependencies[packageObj.name] = {
version: packageObj.version,
integrity: "sha1-000000000000000000000000000=",
dependencies: {}
};
processDependencies(path.join(filePath, "node_modules"), packages, dependencies[packageObj.name].dependencies);
}
}
function processDependencies(dir, packages, dependencies) {
if(fs.existsSync(dir)) {
var files = fs.readdirSync(dir);
files.forEach(function(entry) {
var filePath = path.join(dir, entry);
var stats = fs.statSync(filePath);
if(stats.isDirectory()) {
if(entry.substr(0, 1) == "@") {
// When we encounter a namespace folder, augment all packages belonging to the scope
var pkgFiles = fs.readdirSync(filePath);
pkgFiles.forEach(function(entry) {
if(stats.isDirectory()) {
var pkgFilePath = path.join(filePath, entry);
augmentPackageJSON(pkgFilePath, packages, dependencies);
}
});
} else {
augmentPackageJSON(filePath, packages, dependencies);
}
}
});
}
}
processDependencies("node_modules", lockObj.packages, lockObj.dependencies);
fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2));
'';
};
# Script that links bins defined in package.json to the node_modules bin directory
# NPM does not do this for top-level packages itself anymore as of v7
linkBinsScript = writeTextFile {
name = "linkbins.js";
text = ''
var fs = require('fs');
var path = require('path');
var packageObj = JSON.parse(fs.readFileSync("package.json"));
var nodeModules = Array(packageObj.name.split("/").length).fill("..").join(path.sep);
if(packageObj.bin !== undefined) {
fs.mkdirSync(path.join(nodeModules, ".bin"))
if(typeof packageObj.bin == "object") {
Object.keys(packageObj.bin).forEach(function(exe) {
if(fs.existsSync(packageObj.bin[exe])) {
console.log("linking bin '" + exe + "'");
fs.symlinkSync(
path.join("..", packageObj.name, packageObj.bin[exe]),
path.join(nodeModules, ".bin", exe)
);
}
else {
console.log("skipping non-existent bin '" + exe + "'");
}
})
}
else {
if(fs.existsSync(packageObj.bin)) {
console.log("linking bin '" + packageObj.bin + "'");
fs.symlinkSync(
path.join("..", packageObj.name, packageObj.bin),
path.join(nodeModules, ".bin", packageObj.name.split("/").pop())
);
}
else {
console.log("skipping non-existent bin '" + packageObj.bin + "'");
}
}
}
else if(packageObj.directories !== undefined && packageObj.directories.bin !== undefined) {
fs.mkdirSync(path.join(nodeModules, ".bin"))
fs.readdirSync(packageObj.directories.bin).forEach(function(exe) {
if(fs.existsSync(path.join(packageObj.directories.bin, exe))) {
console.log("linking bin '" + exe + "'");
fs.symlinkSync(
path.join("..", packageObj.name, packageObj.directories.bin, exe),
path.join(nodeModules, ".bin", exe)
);
}
else {
console.log("skipping non-existent bin '" + exe + "'");
}
})
}
'';
};
prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}:
let
forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
in
''
# Pinpoint the versions of all dependencies to the ones that are actually being used
echo "pinpointing versions of dependencies..."
source $pinpointDependenciesScriptPath
# Patch the shebangs of the bundled modules to prevent them from
# calling executables outside the Nix store as much as possible
patchShebangs .
# Deploy the Node.js package by running npm install. Since the
# dependencies have been provided already by ourselves, it should not
# attempt to install them again, which is good, because we want to make
# it Nix's responsibility. If it needs to install any dependencies
# anyway (e.g. because the dependency parameters are
# incomplete/incorrect), it fails.
#
# The other responsibilities of NPM are kept -- version checks, build
# steps, postprocessing etc.
export HOME=$TMPDIR
cd "${packageName}"
runHook preRebuild
${lib.optionalString bypassCache ''
${lib.optionalString reconstructLock ''
if [ -f package-lock.json ]
then
echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!"
echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!"
rm package-lock.json
else
echo "No package-lock.json file found, reconstructing..."
fi
node ${reconstructPackageLock}
''}
node ${addIntegrityFieldsScript}
''}
npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} rebuild
runHook postRebuild
if [ "''${dontNpmInstall-}" != "1" ]
then
# NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
rm -f npm-shrinkwrap.json
npm ${forceOfflineFlag} --nodedir=${nodeSources} --no-bin-links --ignore-scripts ${npmFlags} ${lib.optionalString production "--production"} install
fi
# Link executables defined in package.json
node ${linkBinsScript}
'';
# Builds and composes an NPM package including all its dependencies
buildNodePackage =
{ name
, packageName
, version ? null
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, preRebuild ? ""
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, meta ? {}
, ... }@args:
let
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" "meta" ];
in
stdenv.mkDerivation ({
name = "${name}${if version == null then "" else "-${version}"}";
buildInputs = [ tarWrapper python nodejs ]
++ lib.optional (stdenv.isLinux) utillinux
++ lib.optional (stdenv.isDarwin) libtool
++ buildInputs;
inherit nodejs;
inherit dontStrip; # Stripping may fail a build for some package deployments
inherit dontNpmInstall preRebuild unpackPhase buildPhase;
compositionScript = composePackage args;
pinpointDependenciesScript = pinpointDependenciesOfPackage args;
passAsFile = [ "compositionScript" "pinpointDependenciesScript" ];
installPhase = ''
source ${installPackage}
# Create and enter a root node_modules/ folder
mkdir -p $out/lib/node_modules
cd $out/lib/node_modules
# Compose the package and all its dependencies
source $compositionScriptPath
${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
# Create symlink to the deployed executable folder, if applicable
if [ -d "$out/lib/node_modules/.bin" ]
then
ln -s $out/lib/node_modules/.bin $out/bin
# Fixup all executables
ls $out/bin/* | while read i
do
file="$(readlink -f "$i")"
chmod u+rwx "$file"
if isScript "$file"
then
sed -i 's/\r$//' "$file" # convert crlf to lf
fi
done
fi
# Create symlinks to the deployed manual page folders, if applicable
if [ -d "$out/lib/node_modules/${packageName}/man" ]
then
mkdir -p $out/share
for dir in "$out/lib/node_modules/${packageName}/man/"*
do
mkdir -p $out/share/man/$(basename "$dir")
for page in "$dir"/*
do
ln -s $page $out/share/man/$(basename "$dir")
done
done
fi
# Run post install hook, if provided
runHook postInstall
'';
meta = {
# default to Node.js' platforms
platforms = nodejs.meta.platforms;
} // meta;
} // extraArgs);
# Builds a node environment (a node_modules folder and a set of binaries)
buildNodeDependencies =
{ name
, packageName
, version ? null
, src
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, ... }@args:
let
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ];
in
stdenv.mkDerivation ({
name = "node-dependencies-${name}${if version == null then "" else "-${version}"}";
buildInputs = [ tarWrapper python nodejs ]
++ lib.optional (stdenv.isLinux) utillinux
++ lib.optional (stdenv.isDarwin) libtool
++ buildInputs;
inherit dontStrip; # Stripping may fail a build for some package deployments
inherit dontNpmInstall unpackPhase buildPhase;
includeScript = includeDependencies { inherit dependencies; };
pinpointDependenciesScript = pinpointDependenciesOfPackage args;
passAsFile = [ "includeScript" "pinpointDependenciesScript" ];
installPhase = ''
source ${installPackage}
mkdir -p $out/${packageName}
cd $out/${packageName}
source $includeScriptPath
# Create fake package.json to make the npm commands work properly
cp ${src}/package.json .
chmod 644 package.json
${lib.optionalString bypassCache ''
if [ -f ${src}/package-lock.json ]
then
cp ${src}/package-lock.json .
chmod 644 package-lock.json
fi
''}
# Go to the parent folder to make sure that all packages are pinpointed
cd ..
${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
# Expose the executables that were installed
cd ..
${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
mv ${packageName} lib
ln -s $out/lib/node_modules/.bin $out/bin
'';
} // extraArgs);
# Builds a development shell
buildNodeShell =
{ name
, packageName
, version ? null
, src
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, ... }@args:
let
nodeDependencies = buildNodeDependencies args;
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "unpackPhase" "buildPhase" ];
in
stdenv.mkDerivation ({
name = "node-shell-${name}${if version == null then "" else "-${version}"}";
buildInputs = [ python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux ++ buildInputs;
buildCommand = ''
mkdir -p $out/bin
cat > $out/bin/shell <<EOF
#! ${stdenv.shell} -e
$shellHook
exec ${stdenv.shell}
EOF
chmod +x $out/bin/shell
'';
# Provide the dependencies in a development shell through the NODE_PATH environment variable
inherit nodeDependencies;
shellHook = lib.optionalString (dependencies != []) ''
export NODE_PATH=${nodeDependencies}/lib/node_modules
export PATH="${nodeDependencies}/bin:$PATH"
'';
} // extraArgs);
in
{
buildNodeSourceDist = lib.makeOverridable buildNodeSourceDist;
buildNodePackage = lib.makeOverridable buildNodePackage;
buildNodeDependencies = lib.makeOverridable buildNodeDependencies;
buildNodeShell = lib.makeOverridable buildNodeShell;
}

View File

@ -0,0 +1,3 @@
[
"renovate"
]

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,12 @@
{
lib,
bash,
coreutils,
gawk,
path,
# nixpkgs path
writeScript,
writeScriptBin,
...
{ lib
, bash
, coreutils
, gawk
, path
, # nixpkgs path
writeScript
, writeScriptBin
, ...
}:
let
# Create a script that runs in a `pure` environment, in the sense that:
@ -19,12 +18,12 @@ let
# - all environment variables are unset, except:
# - the ones listed in `keepVars` defined in ./default.nix
# - the ones listed via the `KEEP_VARS` variable
writePureShellScript = PATH: script: writeScript "script.sh" (mkScript PATH script);
writePureShellScript = PATH: script:
writeScript "script.sh" (mkScript PATH script);
# Creates a script in a `bin/` directory in the output; suitable for use with `lib.makeBinPath`, etc.
# See {option}`writers.writePureShellScript`
writePureShellScriptBin =
binName: PATH: script:
writePureShellScriptBin = binName: PATH: script:
writeScriptBin binName (mkScript PATH script);
mkScript = PATH: scriptText: ''
@ -92,5 +91,8 @@ let
'';
in
{
inherit writePureShellScript writePureShellScriptBin;
inherit
writePureShellScript
writePureShellScriptBin
;
}

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:WW0RmSs3k81jSgYLt8dHEiJOxlncPWl3QWvRtmNgtIxvup7h,iv:nw7SP15EVWfS78dJE37msnxAZ/goYb7rGqAKNzhXFP4=,tag:yxVyGUMFczq8cGuU4V/FzA==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiM0FBVkhPc2luMjlpSW1R\nN0NlUU9ZQkxIOVAwa3hlMVg3bFluTjRlRUdRCmMxSkMvZjg2ckUyUThhSC9VOW1H\nZExFY2owcHQ5NzJtUW5pbDFjd2oyaEUKLS0tIG1Fd25acHdYWEdlQkMxajhRQXNw\nTGxJUDdPMlRrQ0t3SkVSaWdZZXJGT0EK7WfQ+6jVzOBToqO9wJby/qaF6kM00hMh\n+Y4A08X/ItLzyfCc5LQ97GQ2VlwXK5+HoD7jNnn//3xeH6YC1VBdkg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhNlpOQ1QydEJuM3pCbEpK\nSDUzVlppNkFnSDJLSU1ITEdWWCtaUEE0THcwCmljSUl0amx2OTBVZXBPMFNGbjJP\nakNQcWlad1R3cDZYWWZpQkJkQmEvUEEKLS0tIFpJOU1GUnNaTnlaL25GRkdxZnhs\nUEhIVEpNWjNOV2FTSmVnRkVCWm90MDgKMvz6QdPRoYb2bPjS9oSOVA5gTfwrgn4q\nIyboQIMV3oAaAs9LSUcUMBvERzQ31JXnHRzrnqtdiNX0NLbIrN47yg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-06T16:09:34Z",
"mac": "ENC[AES256_GCM,data:7iKDT5577mLLeNyi46JHa4AUumqbQm65V3DXqNdNyLWccpIcML8n7jgFNxuK9gTqV2LM6bG18qS1orBJtPdawKnvxJwUaFb3Mo06C2+LVnWG4fT6MV+5eF8y6SM3IngT9BPk7IhTTGWe8lGJ6HTlg+9/f4/cq5NSKfeRgTkDEcE=,iv:T8wjeq2D1J8krhWeQJbVCOPY5sr05z/wMJqvr9onQK8=,tag:XgDTOTa2zv4NiBFN0b3rqA==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/joerg

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:ybX1/Uc+LqfgUoZQqCURgPfsTyzlsO+Xn7z8/0H9v5kyfJYX7PI1VlXVFBgR3Xh+2iuTF+v98PQyYeJOYLk3NTWggZayQQ4ivt0DLdhgG+DRFbeN8GMiqV5NWNhnL2tgLBu9DZViBSpgcbg9aHfI2cagboJnCSqyS2w1i/anvKaEgKa5YucrS4jywVxhBbvON6Oa2v8Hb0f/R8Ldl9HSqMM6o3pQEaYOsTNieNy63h9C4ERP/jIhKSajggpeHENdnuQC7Kavz54faL9xaz0jwRHb1fd+IGTM7fxqbyB5702nKEGytDwKzH0fh6q1HJNHbhWeWyCmGFKOkqywaQjcpJsczP2FIwkZmoui0juTEluNk1KzugP0gxtsuwjUiJlZeJxtZEgsnifLPpHyCaN99jzPjhd1TknT7MWZMVJT/R14bdD+QdwvR8rHK8IMctMGrNsqu3+Crdwu3WSfDH9jEM1zAZQNvLUT13azRABz1rpJvNFnvhDTBwDbUJlLpIQcPOPtVKO0IQeM5EUnCr+oCfBrP/To3mqo82s3,iv:jbY6WK0BcyLlU3Sbo7qNOHfCGU4TjUqTiww546Tyq20=,tag:VklHST51z5XI9+UiASBO9g==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlenFrWW45UXcyd3pwaTE0\nY3ROWWFPdzIwK1JuU2h2NCsyanF1VzhoM1NjCndscHZpTUNmcWc0TDd4V2xHM0lh\ndVNZQW1jMGFNeDdxbDhwdFB1Z3AwdVUKLS0tIGNmbVNMRUZGb1lPcnlrdkhnZ3JX\nM2szRHVydldGN3haV2lhZlFMeUgzcU0KDDwWVSjsua4DKXlqqk2Ns2e1zkzJK2Y2\n8+r8bXkBLJyXqQCQteXBrc5U+0n1KfHVkkvPmuBI3BmcAiVVmr/RxQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJdHEyT3U0TzJQUW9wM2Z3\nYVdTYmRSeUwrZy9iNTVpcmZJMnhOeHlGRGp3CnVYbk15NWxadk9waFdJVFBKa0Vx\nYUtkYWZuYmhabk1xREtDdzFGdUcyaW8KLS0tIGYxcDVuQXZwdk1rVHJOOHljTmVl\nMXNXTHdSam12djE3Z0UyU2dSZDcrRGcKaQnrYuUpSTjOYYHH0EsqnTLHkU5Md4Ro\nUpeJX1GmAoIAUGruB/8jPbMaDQQXbjNLDCCalStlbqMgbgz/Ty4ukQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-06T16:09:35Z",
"mac": "ENC[AES256_GCM,data:2RptHkE/k4JfqdybmnI3sbeEDaaD4bUtEPLuBcpltZjR5EHFYLsEB1Woxlzj2rLqq+8Wr6kWZtsG3uJSxsColUbazJd1CoVJxHpm6tAnM47Mv1YG5PdLwqpwJWji4AI5lAer4ZMfuGDpNbrwvbO3qB8R55r5SYay4b4Yc49wQXA=,iv:ESimFSybysRrgEj+27ECUi6kIklv1IunWVclTjX7C5g=,tag:LONP+cUm5NVcBvgVStZnwQ==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/joerg

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:zCWFFE6+923po+i6g+ehKgC3FdAEhbmFDTbc6VZIXdBqNO7qvC8K1Q34aZVzQ3HaE6l/p5V7Ax0U0xRypQ==,iv:NJhOMcGg55fznrpM6bSqNvr/lOYAsUUVtfK8eJRs0Iw=,tag:6jadN151/70a7BBXsqMClg==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHcHNaTjJlejlJYy90eGFT\nVTloRFV3OVV4enI1OENaeGVpcXpCV0dUenlBCkdONUE3eXhlY1JMRko5Q0VJVFN6\nMkdSR1krYjlJRyswOExRSW9UeUI2czAKLS0tIEJWRDZwRWp1U3V4S0NLOXJDS0ZZ\ncXRFNGxnNXZHNHpvOUpVcTYvM3RoNU0KPgJoJ/22jyUtqGeXfO+DInB3zIwrB+OP\ncjw6Dt7mPYT/OUG6Cq12D6+xMYCm+r4jswtkvWaPhnzGcIOcqMJHwg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUa1IvdklYcENvUzlwdnNi\nbnlidGVvMzZLRS9EU1RzZ0VzMUtvOGRGR25zCklqVTA4T2FIR3l2MER2RjRsbkZH\nRWlxUkYyUjIwSzl5SWJHblMvclZwOGsKLS0tICtaYW83M3lXakJsMFNEc0FjYWdC\nU3ZDUEplYk1tOFRiUUpXTVA0NTUyaHMKdtR+rqRz+Jjf4BfCd5B7ygRLYKTDDRJk\nq0eSNG+i+Xjz/kLWsMpmO4Cevhp0SPyLZV2g2CiDo5vXZQ5Qiy8pSQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-10T09:11:22Z",
"mac": "ENC[AES256_GCM,data:D+NLO8U8mXc4wzQC1OHoba5t+i92P3ZeZy7M8nPhBvnWFznhWBmHRLTI55c8+Q3tkNJI0rBt43+XjC7X1ij36eSza/8O6dh5+jM4UkvFBBJG8ZTPSqakISmPBN1k80qm6G15ELgRrJc0+DNAuuZVuBAwVNUFmaZNx6FmX/G4nRU=,iv:RlhgqQoXAeNFTLRJubVzFJq0wbZwZOeAyZs2nD7IHfg=,tag:6zgWakwYjf93qyMwKlSG9g==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/joerg

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:bcYm9Jx6NS5T2085GmeUJJeLdD1ZtGSfMtXNWcNkeL7F,iv:jR8k0EMO20ZiBXmb1ddJS5x0c95y9vEPvMig0Y0iXBg=,tag:wZBLbCe8ucQSIGrNOjN1jg==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSVWx6TzM4MEpmZ3ExczZo\nNS9kU1Z5NEl1aDdwSzUwSy93anlPQXdOVVVNClBqMENEWUhLVml6dkRZaVk4OU1V\nNjBNV0p2MjFLMDI1c3paOUU0Zndsd28KLS0tIEJZVFA4akVLMzVSanJMcWwweCtE\nZ2h2NE1mdWJNd1VWZDFyT0tvTmlrV0kKfsW5qG12wP+hI/ZCcZNsjv5ububSITLp\n4SzzyeTzpDrGlu/h52szD0VYnB0w3/fF2Ar/lvBYN0y9MXXYUQGdRA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArdmZUaThzQzQ0em9reXJM\nTkNNRlhKRWoxR3dVTXc0TEdXV2pNQytXK3lrCkk1Z1g2d2R6V002d2lXNWtFMmo5\nT2tiTGpyRTE4WXk4c0hYOGdFejBITWsKLS0tIFdib0UzL2dNbXRjZHFYOEVGSWVU\nTDlNN0xSQWgzdFVhV21SSE9JNkM0OGcK2icnV6pvh7PMVp5r51b+Ukgl95XiiTHG\nDjj3M24jEh9UX2bYraGyRNnLh3piQe7Jim3/ZAHSOzl105GulapU5g==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-10T09:11:20Z",
"mac": "ENC[AES256_GCM,data:Ie9j/N4dB6qKtpzPrQROPbsGQCfzYL8dhtptOB0XQw+mh19vpcvWyzLqYOorM1eBKrUWYob6ZHe27KXxN+9RtPe+KFABlFAQRENfPBVPi9Y7/XxMiMQ2gL6JQkvN47Aou/jWhPIOeuCXuEqr4VEOa0F6jPLmS9aPPc95MV/cHxo=,iv:/R67c5rBG3nIm6iAJedPdXL8R+b1RGez/ejzBDW4tf4=,tag:2A9njvLHsAzda+kh8PYj5w==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/joerg

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:U1NXeka1c0Fe55r8D6lAQiujSHbOW6zLjZ85dmtk02q9Szcjj79A6v/jFezqjbQjTtBvBs7tn39/MhQ6CQ==,iv:WPd7Jl4qldLztNUfErlF0dlMo4fe96aJUpiJk0GJePM=,tag:ruIMTtbVOYE7Y4XXhoBSww==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnWHlzTzYwckQwU2VKSDhW\nQmdQdWRSOFgrYk1ZamtDK3JPdkQvcFhrUWhjCjVWbWJYZFUyWnloM1Bram1Rbm1Q\nclZ4NExNOTVCZURFRVhqbGpvNEh5WG8KLS0tIFFkT1ZEOUoxS2NlcFZ0NTFjQmp6\ncUNHOFM1ZWJFaVk4SzJQUzMzbXFXTlEKDUDq9ErdYGm0KYWoXaG8/mVRuW/Sy7hW\nUIzOJ4gdPfB8BxGN5y/Nb0dX+lHN/M4qebcW9KXXPI6Pa3Y6aXCP8g==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEMThwK1FPZUdaNnFmZnJm\nZmx6cWs4QTlwVEd2UFBhdHpIYWdZNW5BMEE0Cjg3bTMxbTFWSGF0UG0rTktrdHpG\ncFBvNDJnY1hWbmxKUUhpRHVpRndhMVEKLS0tIE9BemM0ck5MQWw0YTBRUHpIVjI1\nQTI1c1B3T0FOdkc5MVZZSEhzUFNiNncKuTDwqvXvUcXSX0q8aqlKHr4YewKuL82v\nf/6Mow2JDODVJXtdG36ZBUGQWfCcrSDHVrZjlcoTGyxiHXYh49Y8hQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-10T09:11:23Z",
"mac": "ENC[AES256_GCM,data:ELrw2J+ar72JSJVWN2qJl3SvmtZUIDaeannl75UJN1Z/HZ70F6HDfasu8gtfRraAc5uKuBviyKm83eElwXELV5ZHz5IMkEvFNYOJsAp65YBzfEZuAMoPMFsBYE9U0MTJeYuN62/j13X8Lyld2JPDyPy6INgozFr5XgWfLgkHfrA=,iv:W51r68thFudKRgl9yaSClSG9ByRMfDzFETIWAycBNHw=,tag:8oRyvy53Cvn1u7UH4DuhMA==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/joerg

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:Nx5x4US7N7vKqAhnn2NFwsBiuh9tnAWCBrc6pbNCDQ==,iv:ijhwJFzxggDFPdXVPwKKG0vI8HA8m21xkdFUhHIvCBk=,tag:p1QbTFm/TTyUaGI1s73MIQ==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4dDF3ZEVtTVlyMTRLQ2c2\nOTB6WUxvMXdJZ2xrMnlFOElpYmlEMnorb0NrCkN5MzFmMG9GbTc2N0pvbGtTZFdp\nNjI2YmlodlhSaXMyTENjMG44UkxxYUEKLS0tIEhPZEJhWGozdVBMVWM1QkV5cDAx\nYWRBL3VGU0RFY29HVWtTVjJQZVpIdnMKAftERIDtOMw8k3fbMo+KZJ4JYc5UyL3S\n+16m0hWK1BCXkeL2XFGujkzmrGXJF1bxFXCegdH4fnW2+IMESZZO6w==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4WmJobW8xTU40RUYyYlVj\nclk4UndKRTBMSDNFSmc4RGx1OGJyd0poTFNjClhQV3BQdlVEeU8rME5OUUtlTmYr\nTzZhR2srYnlzL3l5NUZlVmhFV3BOcXcKLS0tIFVMUm5tTVBXckRsVHVsc0ZrSzB1\nWE02MVJZNWtYc201ZDBrc1d2SUptcW8KPSqT5mBQymSksUv3j1y6vgnMuwQKbiXW\nCtzVtF05hv2Z21L+XIV3LOpJ98GGUoJu2uq7qjKIM4CYX+Jj/GS9Nw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-10T09:11:22Z",
"mac": "ENC[AES256_GCM,data:6EeQBxukfz2iNypbkasgDSqb8vMiRaORrA8OvYP5+YNUUguF+jCmSpOUHOM6d2KMF6vGSPLiG15e5IxW7x0QIotMf91Bj46FquzT8PS1hcPTe4WIcg/FHAlLNYqQUgZ9ZlojekkYqs13P8NvFW9pY+MSeYMRQFQLrXvaakcYDHs=,iv:xXALlG13aSaiKiAFUAE/8cZnjh5DaKlinKemoM5tl9E=,tag:x3xVmQwufZav5Yhwxp8cUw==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/joerg

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:vef3eK79BP0R8KS3Ycal0HOfcVTZkB9whZIqjpmgQw==,iv:3i37rWIn5kh6jWQqGFRu0yxyT1Bfa99espOT1DpYB/E=,tag:u90TEhOKTQ8Y8iPvnToeXA==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1K2tkSUE0d0UzYi9XSVdi\nWE5BMVBSTFdLRXJkbk5FaEVvZTUwVjBGT3pRCnVOY3oyK0xIcm4zeXpSb2lzdUZ6\nWDJyUDBDdTdVSmJsYzlBL01qNGtBaW8KLS0tIFoybmZ4cXpZWnhjM2JsMDhNdFVH\nNHhRZTUveDhvRHFGNjhUL0hjNmV2TU0KU9pt2aRKN77uQW5Mq6l/g21YEpokW8Rn\nH0jmBc+n9pPkphojl7VUhm52aBMsUxU94Chko3oHUnTWJXjaS36LAw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBER0c3VCtzb29MUVVvU3p1\naXJXS01uT2NrcmNIT1RyOGJFazA3bFlTNnpvCjVzWmtieVR4ZUV1cWhaR3p3bVNP\ncXp4aWlrZE85cjFRY3RzcThJTlE3SkUKLS0tIGc5UWRINkhhV3lKMjBqYlJDUE5O\ncTY4V05qaGxWM1RYWjFKTXdiM0ZPc00K5nIxr2jMrBdtXJIWjwORM2jXjk7Xcvxu\nIc2KKoOOaQwo7SpAdf/GQm8BoHh2TJcUevfpM0GDII/DyMenhPf1pw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-11T13:38:24Z",
"mac": "ENC[AES256_GCM,data:B2gQaMJIFpJuKpPPdaa6Gw0K9DN4FcoEOybSkA+2kMAqMv5cTPVnG7HV/XY21bQKvmGkAvKa6PhouIp46QyajTmUrUlAGrZrt9W1tBwctJlsHiY7O6she6S02NPpKn9CWurh5XIz8NxcZVcMEwWhc3wQdld47puubUOgHpmfqFU=,iv:Bi3CL4Zb9EZoEmA0e3Qg0B6Kwhc5pvlFlioCcX8Fnco=,tag:gk7VaDhZlbfnv8Xrx6mypA==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/joerg

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:S8Y5p8O9KmheK4fRzoSF5/LqanJ0CxkuMEIqPFfhkFbCaXbjRw==,iv:xVlBzGfAqLDk01UI7oXnR7ukjnKMIn9/avxI/KkLWtg=,tag:sn4N8dXipo63YLT9I40s3g==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHRmxjY0FWTFBpc3BLK1JB\nMGhrVFJzTHVsNGlzR1FyS0JsSzQxMnpSRWtRCkU3bEhidFd0RTVZTzVXemJCTjhV\nSk4ydHJscUd6cExyK3ZmNnowMkR2OVkKLS0tIFBKZnFvaGx1cStNWU9leUk4Ymd3\nM0FFN1ZRYmZJUU8wQ1lKVlI5bzN1TVUKSTK4MflBBEq4a8RnBMEtKGzrKxjZi9wv\nguglBCGX6tvWVkzGmZWWIT9oSimb4pEPlJKH553WBf4aiF5n+kYwsA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1zwte859d9nvg6wy5dugjkf38dqe8w8qkt2as7xcc5pw3285833xs797uan",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLMEpEL1dkM214NmRzdVpw\naUhxSms1ZlZOS0dhdTlVbmkvdFN3MCtFZ3lvCkRYeTFJUHErSFFyK2YvTHdwR3h6\nRVZqNVdkWUh0R09VRDNIVnRNa2FhdFkKLS0tIGxzb3BaQy9vMTZhdjVlVUQ0SEhP\nMHRTWHgxNE1HSVhXM091RVVJUjVmRHMKZD7U1cUvHzvB/rdXRPUAjakxwqrpthUB\nZkLNaY7ws5KNF8dwU72vElPPdz2CWDdIz563u3XV1ZioTkuepgdZyA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-26T12:20:42Z",
"mac": "ENC[AES256_GCM,data:SdZInMlmS/fDQDpxuZUTjWwhjJqzPSJ7UN+fY5vsTdXJ+BRLKxZUpMlahXt85PZukfxE2XxjsnDV+tft80qxSv66HzwSnxsecfrxR9OMwGlG4SEdO0NJe2HFWwcSsXJUlGdkefVhUS5HL97Jr/NN69QTX1Ay/NoOoEdW6R6hb+w=,iv:uc9nlVAbScdxOtvERSiQ0SNfSJ6WK95B37MuL30FY2A=,tag:Swkkc/dQflO7MuTZXvm99w==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/qubasa

View File

@ -1 +0,0 @@
../../../machines/web01

View File

@ -1,24 +0,0 @@
{
"data": "ENC[AES256_GCM,data:ruKBCJYW1Q4ivCQ0uXNyI4QpmHF/kux9OtjKFwt6pC2hV2U=,iv:ZYqvNEhGfJxBEs37fX3Rg7KK9M1PKsTFfZEDd1yEbZk=,tag:37uDB6G4vcwYPzmDxJA5/Q==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1eXhOZVNMYkhVbkhrMnEy\nVm5zd0JDVHpwSzVDQ1gwK1NEa2MyU0VaRVdZClJPdGdlYXUwNDZPb2xEUWJkdGNJ\nS1d1TXFvRWQzdVM0VGY2NHRhZ2dSTTAKLS0tIEt6SmUyRlE3V0dUSFFqbnV0SGp4\nbnU1bXdhMHF4TktaNE1nd2R2U0FLRkUKjp8Gq7zy34Z7NR0qn/GNVG2G0CSQPKvA\nQG0fbZQfpCySnz7O3GG0iA9Zz77aj1OvKE4iXnmejmEg0OO9gHEAoA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age17xuvz0fqtynzdmf8rfh4g3e46tx8w3mc6zgytrmuj5v9dhnldgxs7ue7ct",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsYzAzUm5HTVRNcFFnUENM\nKzlCZno4SlBDcHVkUDNYRXY1cTVQVVRTWmlVCmJMb3QzRm91dkcvMDVvSDFOS3VB\nSUtRSVRrK3BlVjIwU1hBek5FdkxtM28KLS0tIFUzOUNtRmFMV1ZIWjVkbGF5cmM2\nL2NZWVFuNzFIOC9HeWUrRHByWEJzTlkK8GKi6bY4DEWhSnESt+pe2nAm+Omkh/p5\nJkXX0dJIGxuu9VuOUcVIE9m5WmWPKRDS0BinMPZuGSgFYqzn0kV90Q==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2024-06-11T13:38:26Z",
"mac": "ENC[AES256_GCM,data:caOsb2taskbJC8iB9+J+lVHCQGDYt/XZiOo1cKSdhtrkQJ/BJOinZOY6cBGCzv57ewBg6FT9XIEQAqcYzChs910gGFklVAlmwo8BEMFdhg/VTg/qDbBC3AmTGuOepVbFRbsA714UiHuAmbt+pfpe3+wAh9oEEpNRmLc9x8MhNTo=,iv:kKtI4yF7gqm1pXQKIifhJX0+Ugk5FdXNjW39t9cnTf4=,tag:2FTptmViYqx/e0yjOfSndQ==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.8.1"
}
}

View File

@ -1 +0,0 @@
../../../users/joerg

View File

@ -1,14 +1,16 @@
{ self, inputs, ... }:
{
flake = inputs.clan-core.lib.buildClan {
meta.name = "infra";
clanName = "infra";
directory = self;
# Make flake available in modules
specialArgs.self = {
inherit (self) inputs nixosModules packages;
specialArgs = {
self = {
inherit (self) inputs nixosModules packages;
};
};
machines = {
web01 = {
web01 = { modulesPath, ... }: {
imports = [ (./web01/configuration.nix) ];
};
};

View File

@ -1,8 +1,5 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p coreutils sops openssh
# shellcheck shell=bash
# shellcheck disable=SC1008,SC1128
set -euox pipefail

View File

@ -1,8 +1,5 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p nix jq bash rsync
# shellcheck shell=bash
# shellcheck disable=SC1008,SC1128
set -euo pipefail

File diff suppressed because one or more lines are too long

View File

@ -1,34 +1,36 @@
locals {
hostnames = [
"@",
"git",
"mail",
"cache",
"matrix",
"www",
"docs",
"metrics",
"buildbot"
]
}
resource "hetznerdns_zone" "server" {
name = var.dns_zone
ttl = 3600
}
resource "hetznerdns_record" "root_a" {
zone_id = hetznerdns_zone.server.id
name = "@"
type = "A"
value = var.ipv4_address
resource "hetznerdns_record" "server_a" {
for_each = toset(local.hostnames)
zone_id = hetznerdns_zone.server.id
name = each.value
type = "A"
value = var.ipv4_address
}
resource "hetznerdns_record" "root_aaaa" {
zone_id = hetznerdns_zone.server.id
name = "@"
type = "AAAA"
value = var.ipv6_address
}
resource "hetznerdns_record" "wildcard_a" {
zone_id = hetznerdns_zone.server.id
name = "*"
type = "A"
value = var.ipv4_address
}
resource "hetznerdns_record" "wildcard_aaaa" {
zone_id = hetznerdns_zone.server.id
name = "*"
type = "AAAA"
value = var.ipv6_address
resource "hetznerdns_record" "server_aaaa" {
for_each = toset(local.hostnames)
zone_id = hetznerdns_zone.server.id
name = each.value
type = "AAAA"
value = var.ipv6_address
}
# for sending emails
@ -41,10 +43,10 @@ resource "hetznerdns_record" "spf" {
resource "hetznerdns_record" "dkim" {
zone_id = hetznerdns_zone.server.id
name = "mail._domainkey"
name = "v1._hostnamekey"
type = "TXT"
# take from `systemctl status opendkim`
value = "\"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdw2gyAg5TW2/OO2u8sbzlI6vfLkPycr4ufpfFQVvpd31hb6ctvpWXlzVHUDi9KyaWRydB7cAmYvPuZ7KFi1XPzQ213vy0S0AEbnXOJsTyT5FR8cmiuHPhiWGSMrSlB/l78kG6xK6A1x2lWCm2r7z/dzkLyCgAqI79YaUTcYO0eQIDAQAB\""
value = "\"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpQeJirqh8VFGHRQBemqF5CeicC/5qHJn3vqKkVIOQNqkgp7IE+EZDg+MXoxMQZEJ0RbO0JpZZgYpOf3jf8o5w56WbE4dbpbi+9112R57k5w41R16Q0EUjf7MbrLJqcF6mtf+3bPklF9ngdcWhgN024YfhR9SlebCOapCVYqVt8QIDAQAB\""
}
resource "hetznerdns_record" "adsp" {

View File

@ -1,8 +1,6 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p coreutils sops openssh nix
# shellcheck shell=bash
# shellcheck disable=SC1008,SC1128
set -euox pipefail
if [[ -z "${HOST:-}" ]]; then
echo "HOST is not set"

View File

@ -0,0 +1,76 @@
#!/bin/sh
set -eu
installNix() {
if ! command -v nix >/dev/null; then
echo "Installing Nix..."
trap 'rm -f /tmp/nix-install' EXIT
if command -v curl; then
curl -L https://nixos.org/nix/install >/tmp/nix-install
elif command -v wget; then
wget -O /tmp/nix-install https://nixos.org/nix/install
else
echo "Please install curl or wget"
exit 1
fi
sh /tmp/nix-install --daemon --yes
fi
set +u
. /etc/profile
set -u
}
patchOsRelease() {
cat >/etc/os-release <<EOF
ID=nixos
VARIANT_ID=installer
EOF
}
installTools() {
env=$(
cat <<EOF
with import <nixpkgs> {};
buildEnv {
name = "install-tools";
paths = [
nix
nixos-install-tools
parted
mdadm
xfsprogs
dosfstools
btrfs-progs
e2fsprogs
jq
util-linux
];
}
EOF
)
tools=$(nix-build --no-out-link -E "$env")
# check if /usr/local/bin is in PATH
if ! echo "$PATH" | grep -q /usr/local/bin; then
echo "WARNING: /usr/local/bin is not in PATH" >&2
fi
mkdir -p /usr/local/bin
for i in "$tools/bin/"*; do
ln -sf "$i" /usr/local/bin
done
}
applyHetznerZfsQuirk() {
if test -f /etc/hetzner-build; then
# Hetzner has dummy binaries here for zfs,
# however those won't work and even crashed the system.
rm -f /usr/local/sbin/zfs /usr/local/sbin/zpool /usr/local/sbin/zdb
fi
}
installNix
patchOsRelease
installTools
applyHetznerZfsQuirk

View File

@ -1,23 +0,0 @@
From 43b15f8757a7f8de0340cc977ff9619741a5d43f Mon Sep 17 00:00:00 2001
From: Brian McGee <brian@bmcgee.ie>
Date: Mon, 1 Jul 2024 14:20:22 +0100
Subject: [PATCH] fix: configure toml key for global excludes
Signed-off-by: Brian McGee <brian@bmcgee.ie>
---
config/config.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/config.go b/config/config.go
index d9e281f..be5c991 100644
--- a/config/config.go
+++ b/config/config.go
@@ -10,7 +10,7 @@ import (
type Config struct {
Global struct {
// Excludes is an optional list of glob patterns used to exclude certain files from all formatters.
- Excludes []string
+ Excludes []string `toml:"excludes"`
}
Formatters map[string]*Formatter `toml:"formatter"`
}