11 Commits

Author SHA1 Message Date
javalsai 0cd381a41c docs: document installation, secrets and setup steps
Check / Nix flake (push) Failing after 10s
Lint / Nix expressions (push) Failing after 11s
2026-05-04 01:59:47 +02:00
javalsai 3f1ef7052e nixos/services: make dns configuration easier 2026-05-04 01:59:47 +02:00
javalsai e83b3bae26 nixos/service: add dns (bind named server) 2026-05-04 01:59:47 +02:00
javalsai 744921de6e nixos/programs: add bind utils 2026-05-04 01:59:47 +02:00
javalsai 0b55eff920 lib/ssh: add more ssh keys 2026-05-04 01:59:44 +02:00
javalsai dd7ad60710 nixos/services: add gitea server
Check / Nix flake (push) Failing after 9s
Lint / Nix expressions (push) Failing after 10s
2026-05-04 01:56:34 +02:00
javalsai fd18ae4a78 nixos/services: add nginx base configuration 2026-05-04 01:56:34 +02:00
javalsai d7deaa187c nixos/networking: add own fqdn to extraHosts 2026-05-04 01:56:34 +02:00
javalsai c6d66902bb nixos/hosts: add tuxcord-vm host configuration 2026-05-04 01:56:34 +02:00
ErrorNoInternet 4704a887fa nixos: separate openssh firewall port 2026-05-04 01:56:34 +02:00
javalsai eaaffcc289 lib/ssh: add more ssh keys 2026-05-04 01:56:32 +02:00
43 changed files with 217 additions and 1109 deletions
-1
View File
@@ -1 +0,0 @@
use flake
+1 -2
View File
@@ -1,4 +1,3 @@
# Nix
/*.qcow2
/.direnv
/result
/*.qcow2
@@ -1,19 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA sLlStq5Hzb2JNQubLtMk5/kyIp81aTyjUB/Ysv1gRR0
lTLWsvT5Oxk8ut/g+o9o0DMOIQVDmi9o4EO0fYeIToo
-> ssh-ed25519 zNC8SA G0XcS2gzF0RopI2DqkWaTYXwjUpkVtdrxSQ+p8bfE0w
pZVIg/1P8BbnpRfV5F0FG3xgLSiA8M+nosQ8iNeYmcU
-> ssh-ed25519 EiAAKw qWmO0IjKoUFVxbxFUx36JIhME2PU7lkD+3agKO7+6nA
yEIw8IzQmM8C9dZoPajtvdUOF5kJ/C+rtgLczcmP1bs
-> ssh-rsa eFi+Zw
O5XRvS+Y/1mm9nQ7IZmxEp7RmFjAH0OTKPkRTME7BybnePPZLL0l6wMP26hx88Nv
dOqdaS07Xb26EIgCS/4xCY4sPWZNEfAfnDVoF4/SNbmfbN0XpNpR981AWcxiTL35
Fngk0lPa1NtuUH4S4zTda21kXHE0zv2mYLNMuek8dTrUd2piC+Z0WJJdrG1LK0hN
dDuLzX/mNibNXDvYxyD6mtkO2S1wO9QL88ucNZptT29vcaD48EZM/SsAwgf3OoqH
kd7jSTTdZ/yk8ccTMiT5eskQ3ZZcqc7JaF+M2d88DP6LcSaJnNzyVSEMAHHfpoY1
/kHxZ88/ehwPDXrp0bL448jdPuWqPSerzCWyyZFbc8Jj6zRUtC5joL0Vq2Rqs+EH
rmKMfi1l2+utleGYfCyHI5/czsMhJ2jXLGPguWQQdixNtb/RWFw6DeRP9xdO9QJR
LkoAFgv0ykP+L+C6sA7bpJqIGNftl4x8OUQxrKtf3YQ8K2LhUZb23JPn4Ob/QXo/
--- W7eUDhB/RBUYV1gaM4ktPEOVU6l5IRgOoRDpKKpvAnM
O\òŒMúOýJä ÍÅ!ÒHûËÄpK¥Õ:gßÙ[6™M¡VÞÃbYæÌí;è€F'¡#ä7&Žs1„ 󨱉6º²5_nÂ’Ô.¼qñ'à˜ƒq®6Êf-ÖÄW™w›½ß#5³¯6ˆ¼ŸêªrÒð„Ð#œÅÄ€=4EÎËlžÕÿ[
Binary file not shown.
@@ -1,7 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA 3CWPYLgoTMGb9gBbDzZIQxYJ9Gfm49g6lqQyqlegUDQ
ryhsPP5+Byus2e5GSXDJlKYX1o3HfQ87CLRv2htU4n4
-> ssh-ed25519 EiAAKw B2uGdkeC3OZISN2iH2DR1J7L3/mbuFvebzqaTdAURCw
ze0X/MmHP78rRqAn0O3VBtnMJsiOXPk8RIe82tdQMeg
--- kLBxPuJdbPmJ1Lz3iBu8EPItdZtpNHIyV6pz1QzhcUY
ä3ÛÿÉèŸP>gòh@­ö•AZ’üz-í6R€¸zèÚ¢[ÇÝÍòã¿y?•ÉŽUSNÝ©&ú#}ÝR+o?.B¶&´5]ÇW€OΉPuh‹½ŽÞ=t¶5|¿×“s×€ú&!­‰Î-æTÝSÆfÕ™-j"#žwzºš›ãjö¯“HŒí
Binary file not shown.
Binary file not shown.
Binary file not shown.
+31 -17
View File
@@ -1,20 +1,34 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA 8rfiRx7+Gr9BtiSXsVEs2W+pXoms6ynODC1TL90+Wi4
/uMnYMJovbaPjwX1qCAtIokov40RYIAm2Mup5XKBJvw
-> ssh-ed25519 zNC8SA FlxMK7kMYnKHY9MBJ+HYDI4GNS0nSgZxVuRe4yTWBgg
HPOV31k8Ueb1W5usG7iLXDQxyAlISrgHThddHpGY2+s
-> ssh-ed25519 EiAAKw Bu7+NJXivoRA07glNWUlBGu03J0ueth7XDU7SWQYT30
r/DBmf4TRDJBgFF0KdeHuKL5hLdU1z6HtfAAVbc6Y0I
-> ssh-ed25519 Wl2fDA dM0TgKtswZcbEV9tGGY26YCksV2xadHWXv7D/KksAWk
1vCcuHmVP2xiHd/7hh0z2Hiq/EeA8uvdsRtQReC5hNY
-> ssh-ed25519 zNC8SA uTO/3ePjgiKqk3jeRGZX5D3LjzhSBlp2rD2ZakKmfX0
tVkEEcP/KfD9x52l7iz5F3hKK0LSckjXWK5YP2aeBt4
-> ssh-ed25519 EiAAKw Etu0I4IzJ3BB2SzCeiexx+dhcLUO5d2Ws+WiJyLk/Sw
9GBcZPsIXO3mXbri3lFYjtBBu0wFYul6hKsCvBKVLFs
-> ssh-rsa eFi+Zw
Nu4gAM/vbh0kpEUIaT4P6iTe9qFFM/9IVxiiKPYHdPnCmPJHrug1afLLFrrrpqkd
o1NrfYIM9gW6jl5QMCcP5DpzMTppokX0P1Tz1ZeOEtZUVtGeZ7Q2wmL4zftwmG9J
qoDjsCd0z6MPDUdU46qc7kjQBhOwGLfHXTfGLXGNZxqj0oLvEoEKpdvFNBvMSyxK
oGZRwGsHQcUXKhCPtf6PVtSkHMABzpUAhgS8oqjp4RVurD0lcrPgsx8pSRRarfyE
ll1QbFCjftuJfeIEshgRkaLGjIQpZDFA3w2XMqDddFz5H/9Ak+F8/rkNnUrN2x4M
amca8s4Sbls6RjyysarIytilCtpaKEI2sgkD2fERao6ayTSnWF45qqh635OLaP5A
b7qcru9gO0C3Ik+UuiZMgovxo/+yBYe3+8x8q/uKR4apPAkt/2q28Uilw1WboIEB
rIjBr0BN1JeHvkiyljJGcvGf5jHdmOrpQu/L1xuSDjsTnh+U6BshQC8bbkJNsVoL
uOZsBC+IMHdX2h9Jq/CF/L3BsxDW+dULk04JQbDeM85Mrxxdrv2X3w7AW8YU2KS+
Xg8LnzH01z4Nfs89uysM/lsWptc9qMeaK9o0oHC+tSJH4Ch43MejbmFYjFibHaCm
krQM7dAGIJwc/o0+ykaCrbXSvXAyfd6Nw1izou2ZcDRI7mTipOZO8F949SIk//Rc
UJgPLqpGwScEfrHf4f6tySC4LmD0bPIV1xDpmmXcS7c83E9+iVOtb5Y1In6CQrF1
XZQCb9MkPySbuicwR022CySb+lc7Ru44RdqBgV1e+wphyZCoqCk09i18egV3hNs6
iEul3M8dqV27yRKrWIUD5jT2tUszTNJfreiuZl9eDmLkcVWExkWzqWPUFJ48hQiZ
89Z4Evn04vZGoeL67K5q93lSRHz109zT/KIJSQMZpbaecGAoiZDM8Mdq3KzawGSG
ENQazx6lnGoMccvxFhjrVqfYj3U4S/pnCow5fatvkBQSyysL63UxE5ivcFUHHppB
--- GCTLfa/BICL9AWTaqGC13M101Z8sqSqPP4ysJVv5zvg
]
ý­¢Ôÿi¹‡7c·f`b@%X”¿J )û[<+;x-ÇKmTõ@ãÌ„ýŸK]7sc*ë­Ÿ‡¼2Ý®5
-> ssh-ed25519 QovoLQ wgg0cFlYEVafE3rXK4GrID3RTatZdKPYzsjT18WskFM
bgv+7an3xgdqf6WaiB1FFkXObcykUnvH6lJmX5gFJkQ
-> ssh-rsa OFkEIg
IIQbFB6VUwbB+ZtKR7Ayg9Im6vMU1AzqHT8CBagA5fwJ7Vp1GuX1X9SxL9hMPkd3
4osEbSu3JJDMwfC6AfFtcEjmxjmRYyiYlzmIjhVEsaTlwyeucAPd+fdj+TPjHidZ
dffizNEOiENY49jlmWTjMqYKnBsSP9GfH4ZsKpCaWMm2h9p687weuXFfbYfjYMII
a3C4iG8m+mZ4crYTKZu6WPbnHn9g0pMxZBs4v6MnBHk6eEJ0uiJvrzYApoFE5om7
9AknL27ra/+A1UQl+1kzLT+IivJa8FCfZ+zF1RYLRvSATlIzCqCiBiayAsVtQg5O
girBRnlAJTPisszyoAhsqbECvD6bJfwlTW0STg/M1u3ZPMTGL4V0gJgynANmjb7Y
TXd11zuhjRYgOBAj09trQFTmmwIgPvvu8+VXNDNPAp02ffBT8kMUvSEik98/35x1
Dwvm38t05O6nqyHUF957CRVTzPQPAnb5Cd+Rw/joID2YPyFN9IZwE4mi2Bf3zdZo
roxtqCupmWkpxMNN7GZJrmCE/Lh6YV4DgUd6VNQc7QlGsq5K4XRT7aa+s+17cC8e
HCxQfGM8sMe9T6IK+K4p6qTqluyI/X0r95kGfzhNmgzufc44i6X497i3fDSVoLpx
Uo7Ao3QRNPyaUXcqTTIg8Kx9YiLQC3tDblVJjIZU89o
--- Vb9o/bhuN6XXjfK04haEEUXnuIA02j4GH9PmAh0ayN8
óE¬dGs;’ްÀ± ü
ñ,OHˆÿœˆ{²¶>ú*wAÃLÌÄ\©0SQöÖ*{6fô‰+Xš¨.
+7 -17
View File
@@ -1,25 +1,15 @@
let
inherit (import ../lib)
users
adminSSHKeys
attrsToList
getSSHKeys
;
users = import ../lib/ssh/keys.nix;
tuxcord-ca = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPxiko5Csyq9UODglYzLBvRfxkhQu9GXP7SH2BpC8G/7";
in
{
"ntfy.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"ntfy.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
# tsig-keygen etc.sub.domain.tld.
"dns/tuxcord.net/tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"dns/nix.tuxcord.net/nix.tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"dns/tuxcord.test/tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"dns/tuxcord.test/sub.tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"dns/tuxcord.net/tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ [ users.error users.javalsai ];
# "dns/tuxcord.net/XXX.tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ [ users.XXX ];
"dns/tuxcord.test/tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
"dns/tuxcord.test/sub.tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
}
// builtins.listToAttrs (
map (user: {
name = "dns/tuxcord.net/${user.name}.tuxcord.net.key.age";
value.publicKeys = [ tuxcord-ca ] ++ getSSHKeys user.name;
}) (builtins.filter (user: user.value.ddns or false) (attrsToList users))
)
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 22 KiB

-12
View File
@@ -1,12 +0,0 @@
{{template "base/head" .}}
<div role="main" aria-label="{{if .IsSigned}}{{ctx.Locale.Tr "dashboard"}}{{else}}{{ctx.Locale.Tr "home"}}{{end}}"
class="page-content home tw-mb-8 tw-px-8 center" style="height: 100%; flex-direction: column; display: flex; align-items: center; justify-content: space-around;">
<img width="500" height="500" src="{{AssetUrlPrefix}}/images/full-logo.svg" alt="{{ctx.Locale.Tr "logo"}}">
<div class="hero">
<h1 class="ui icon header title">
{{AppName}}
</h1>
<!-- <h2>My own gitea server 😎</h2> -->
</div>
</div>
{{template "base/footer" .}}
-51
View File
@@ -1,51 +0,0 @@
@import "/assets/css/theme-forgejo-dark.css";
/* :root { */
/* --is-dark-theme: true; */
/* --accent-color: 221, 85, 85; */
/* /1* #d55 *1/ */
/* --gitea-color-primary-dark-4: 221, 85, 85; */
/* --accent-color-secondary: 96, 72, 10; */
/* --accent-color-hover: 170, 68, 68; */
/* --color-primary: rgb(var(--accent-color)); */
/* --color-secondary: rgb(var(--accent-color-secondary)); */
/* --button-color: rgb(var(--accent-color)); */
/* --button-color-hover: rgb(var(--accent-color-hover)); */
/* } */
:root {
--is-dark-theme: true;
--color-primary: #d162a4;
--color-primary-contrast: #fff;
--color-primary-dark-1: #ba3283;
--color-primary-dark-2: #b55690;
--color-primary-dark-3: #ac2c79;
--color-primary-dark-4: #a30262;
--color-primary-dark-5: #8a0253;
--color-primary-dark-6: #710144;
--color-primary-dark-7: #570135;
--color-primary-light-1: #d776af;
--color-primary-light-2: #dd89bb;
--color-primary-light-3: #e29dc6;
--color-primary-light-4: #e8b1d2;
--color-primary-light-5: #eec5dd;
--color-primary-light-6: #f4d8e9;
--color-primary-light-7: #f9ecf4;
--color-primary-alpha-10: #d162a419;
--color-primary-alpha-20: #d162a433;
--color-primary-alpha-30: #d162a44b;
--color-primary-alpha-40: #d162a466;
--color-primary-alpha-50: #d162a480;
--color-primary-alpha-60: #d162a499;
--color-primary-alpha-70: #d162a4b3;
--color-primary-alpha-80: #d162a4cc;
--color-primary-alpha-90: #d162a4e1;
}
.navbar-left > #navbar-logo.item,
.navbar-right > #navbar-logo.item,
.navbar-mobile-right > #navbar-logo.item {
padding: 3px;
}
+1 -7
View File
@@ -16,19 +16,13 @@ To test the environment, you can launch a virtualized NixOS system derived from
nix run '.#nixosConfigurations.<system>.config.system.build.vm'
```
Here, `<system>` refers to the hostname of the system you want to test (e.g., tuxcord-test).
Here, `<system>` refers to the hostname of the system you want to test (e.g., tuxcord-ca).
Note that this will create a `qcow2` image file in the current directory. Nix will automatically manage changes to the configuration and update the image file accordingly while keeping part of its mutable state (e.g., root bash history).
> [!WARNING]
> Not all changes are applied automatically. Updates such as user passwords changes or modifications to the filesystem layout will require deleting the image file so that Nix can re-create it from scratch.
# Access
The initial password for the `root` account is `tuxcord`.
SSH login is enabled for the configured user keys, if using the VM test configuration, yo will have to use the bridged IP.
# Tooling
Tooling used to aid in development.
+1 -1
View File
@@ -42,7 +42,7 @@ Host specific configuration can be found at `nixos/hosts/tuxcord-XX`. This is us
To learn how to get started, refer to the [Getting Started guide](./GETTING_STARTED.md).
The guide contains basic instructions as to how to use Nix for this repository, as well as tools to help in certain tasks, some of this tools might be assumed across document resources.
The guide contains basic instructions as to how to use Nix for this repository, as well as tools to help in certain tasks, some of this tools might be assumed accross document resources.
It might also be useful to read the [installation section](#installation) to learn how to configure your testing environment.
+3 -9
View File
@@ -6,20 +6,14 @@ Secrets are managed with `agenix` in the `agenix/` directory. This allows to dec
The `agenix` help menu is already very helpful, but here you have a survival guide:
- `agenix` commands should run relative to the `agenix/` directory.
- `agenix` commands should run relative to the `agenix/` direcotry.
- `agenix -d` allows you to descrypt such file if you possess any of the decryption keys.
- `agenix -e` decrypts (if present) and opens the file in your editor to re-encrypt when exited.
- `agenix -r` re-encypts `*.age` files in the case you ever change its decryption keys.
# Secrets
There is a `ntfy.age` secret file which contents look like:
```sh
NTFY_TOPIC=readable-name_XXXXXXXXXX
```
This secret file is meant to be sources by shells before using [ntfy.sh](<https://ntfy.sh/>) to push important notifications. This topic could contain sensitive information and must be kept secret amongst administrators.
<!-- TODO: missing ntfy.sh secret docs -->
## DNS TSIG Keys
@@ -30,5 +24,5 @@ These keys can be generated using `tsig-keygen <key-name>` (historically they we
When DNS is enabled for a host, it will look for `dns/${fqdn}/${zone}.key` secrets.
- The key whose zone matches the `${fqdn}` will be allowed to tramit updates for all the domain.
- Keys restrained to a specific `${zone}` will only be allowed to edit records of such zone.
- Keys restrained to a specific `${subdomain}` will only be allowed to edit records of such subdomain.
- All keys must be named with the zone they affect, final dot included, so that (e.g. `tuxcord.net/javalsai.tuxcord.net.key` must be generated by `tsig-keygen javalsai.tuxcord.net.`).
+1 -7
View File
@@ -2,13 +2,7 @@
The first configuration of the server needs some configuration of its mutable state:
Setup also heavily relies on the secrets configured, make sure you [understand agenix](./SECRETS.md) good enough.
# Root Password
The `root` password is `tuxcord` by default on all system configurations. For security, it's important to remember to change it as soon as an installation is done.
The root account is intended to be kept active in case there ever is the need to perform a TTY login. But this will be rare so do keep a security complex password saved somewhere and don't share it beyond the necessary amount.
Setup also heavily relies on the secrets configured, make sure you [undestand agenix](./SECRETS.md) good enough.
# SSH Keys
-5
View File
@@ -52,11 +52,6 @@
formatter = pkgs.nixfmt;
};
flake = {
lib = import ./lib;
pins = import ./npins;
};
systems = [
"x86_64-linux"
"aarch64-linux"
-24
View File
@@ -1,24 +0,0 @@
rec {
toList = x: if builtins.isList x then x else [ x ];
nameValuePair = name: value: { inherit name value; };
mapAttrsToList = f: attrs: builtins.attrValues (builtins.mapAttrs f attrs);
attrsToList = mapAttrsToList nameValuePair;
getSSHKeys =
username:
if (builtins.hasAttr "ssh" users.${username}) then
toList users.${username}.ssh
else
builtins.warn "user ${username} declared without ssh keys" [ ];
users = import ./users.nix;
adminSSHKeys = builtins.concatLists (
map (user: getSSHKeys user.name) (
builtins.filter (user: user.value.admin or false) (attrsToList users)
)
);
}
+8
View File
@@ -0,0 +1,8 @@
{
error = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDzdpxex2GlFVf5G2qsh3Ixa/XCMjnbq4JSTmAev7WYJ error.nointernet@gmail.com";
javalsai = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDFjavnLqxIzFLIUpUWDOwhlYeoII4Qk1/9e0yWWxD/P";
max = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDxVfJhzPDZ108UjB3Vj/akzlzYn27kyAw29AuYAr7gvG5vrqhLUYYmK8t+ZVWVpc1g6cK7OF1oUn2E5Qfmy6wqyZQXftAZ4OcRS0MB71W1bAcRq3rGe6KQDm8RSEeygX+zO+2Z6zQmVWgPr/I+JFQZ8wiWdP8X8djqTRdhqUD+SR3ZgTcnY3aLmeB/I56rcZQ3lKIeg/pEsyQ8weptlV0rTWamna6Z7Nw48VwWNSI+6EqfW2/4/edm0Ue8jMNqNZ0yx+kHJbudPgZgSR1SiR2rqlEEUaiQJQQV3VdY4DhGm7143ZSKUxyKlfTuQ7qR1zSIg6f5V71A37ik9YiSbBlOZO86swR4qHESoMNf608IuqRt2NdALHwozFPUCu16qnhu5JTk8twSAzrAhOk5zWQj1LYMoQEBhcFSmwir/1gE71NSjYtqXGVAdfkVmZ4uqG5+a1D7H3VXWOqu/j839M045O1ZBY6X3lKDsEJ1Z1+LCl/NojWnvPtJUHYI6+SdQ6k=";
vectorum = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwfPaylCSN7ZqB6Trz8CmQlyzf0NUIy06uschdIOkdzjUNe/dPGbyEFZy/4SDBhg585x8hwfhfYjLGrneYq+O42DBDTDKxduWnIdl5zgPRqt7jB59jkukf9WUdpUdZsKCM5K97HCnizNEKGRnYllVPVQSapPhOm5dZlUD9YVv1UqbDuxtWOLvArkL52e9T+yL6FagRg6NPqA70MXPMk+S2H7lotFVxP2Eg//BCaQ0/H1vhNy6P4N6LLq3sVK1DSJyd2v8zHkdb2Zo0/Ygukol10KizSsEcihm8+bXp699uSgWIsaIQgDZlE1yx2iabmzQST1kL9+USnZZBZ+KxwtLCCI8mpCv6sxlhq2Zzim5HvsyMYM+zdHWIn1s2c6mEl4ntBAB4s5wAggS5Gjh/BfJLSvGsTFMC/XYX4gWFXynY5NlcopeENL2Afg4gbQvKkxYkWB/TMZWuqj5c5kCy+7F0881DpYxapq6kQ6IE4gkGiEQdhVFGWEFoV/k9iHrl6aanqvFtvuBHHgkXAGPpHAZDVZdp9lU0tqNQIM/eGINq4Or6wd9XDYyj5ezDEBxx1pPgweUDZrNe9+vKR+3AwbzB/XQPxTCcjd4d7Yx58jPLflFP1dDYT+3bvp+vA7UpHcJnISbVNu0SiSaIqLYhwDj1od5l6JDfRCqnMF1T59nRCQ==";
pickzelle = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUYQUWoL8iGc+PSrRrHyNwcOcmgGwPvJAM9HRJkPqcW pixel@DOOM-Machine";
}
-26
View File
@@ -1,26 +0,0 @@
{
error = {
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDzdpxex2GlFVf5G2qsh3Ixa/XCMjnbq4JSTmAev7WYJ error.nointernet@gmail.com";
admin = true;
ddns = true;
};
javalsai = {
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDFjavnLqxIzFLIUpUWDOwhlYeoII4Qk1/9e0yWWxD/P";
admin = true;
ddns = true;
};
max = {
ssh = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDxVfJhzPDZ108UjB3Vj/akzlzYn27kyAw29AuYAr7gvG5vrqhLUYYmK8t+ZVWVpc1g6cK7OF1oUn2E5Qfmy6wqyZQXftAZ4OcRS0MB71W1bAcRq3rGe6KQDm8RSEeygX+zO+2Z6zQmVWgPr/I+JFQZ8wiWdP8X8djqTRdhqUD+SR3ZgTcnY3aLmeB/I56rcZQ3lKIeg/pEsyQ8weptlV0rTWamna6Z7Nw48VwWNSI+6EqfW2/4/edm0Ue8jMNqNZ0yx+kHJbudPgZgSR1SiR2rqlEEUaiQJQQV3VdY4DhGm7143ZSKUxyKlfTuQ7qR1zSIg6f5V71A37ik9YiSbBlOZO86swR4qHESoMNf608IuqRt2NdALHwozFPUCu16qnhu5JTk8twSAzrAhOk5zWQj1LYMoQEBhcFSmwir/1gE71NSjYtqXGVAdfkVmZ4uqG5+a1D7H3VXWOqu/j839M045O1ZBY6X3lKDsEJ1Z1+LCl/NojWnvPtJUHYI6+SdQ6k=";
admin = true;
};
vectorum = {
ssh = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwfPaylCSN7ZqB6Trz8CmQlyzf0NUIy06uschdIOkdzjUNe/dPGbyEFZy/4SDBhg585x8hwfhfYjLGrneYq+O42DBDTDKxduWnIdl5zgPRqt7jB59jkukf9WUdpUdZsKCM5K97HCnizNEKGRnYllVPVQSapPhOm5dZlUD9YVv1UqbDuxtWOLvArkL52e9T+yL6FagRg6NPqA70MXPMk+S2H7lotFVxP2Eg//BCaQ0/H1vhNy6P4N6LLq3sVK1DSJyd2v8zHkdb2Zo0/Ygukol10KizSsEcihm8+bXp699uSgWIsaIQgDZlE1yx2iabmzQST1kL9+USnZZBZ+KxwtLCCI8mpCv6sxlhq2Zzim5HvsyMYM+zdHWIn1s2c6mEl4ntBAB4s5wAggS5Gjh/BfJLSvGsTFMC/XYX4gWFXynY5NlcopeENL2Afg4gbQvKkxYkWB/TMZWuqj5c5kCy+7F0881DpYxapq6kQ6IE4gkGiEQdhVFGWEFoV/k9iHrl6aanqvFtvuBHHgkXAGPpHAZDVZdp9lU0tqNQIM/eGINq4Or6wd9XDYyj5ezDEBxx1pPgweUDZrNe9+vKR+3AwbzB/XQPxTCcjd4d7Yx58jPLflFP1dDYT+3bvp+vA7UpHcJnISbVNu0SiSaIqLYhwDj1od5l6JDfRCqnMF1T59nRCQ==";
};
pickzelle = {
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUYQUWoL8iGc+PSrRrHyNwcOcmgGwPvJAM9HRJkPqcW pixel@DOOM-Machine";
};
}
+15 -10
View File
@@ -28,8 +28,6 @@ in
./vm.nix
];
age.secrets.ntfy.file = "${self}/agenix/ntfy.age";
nix = {
package = inputs'.nix-super.packages.default;
@@ -99,15 +97,22 @@ in
extraHosts =
let
subdomains = [ "git" ];
inherit (config.networking) fqdn;
hosts = [ fqdn ] ++ map (sub: "${sub}.${fqdn}") subdomains;
subdomains = [
""
".git"
];
in
lib.concatMapStrings (host: ''
127.0.0.1 ${host}
::1 ${host}
'') hosts;
builtins.foldl' (
hosts-acc: domain-prefix:
let
host = "${domain-prefix}${config.networking.fqdn}";
in
hosts-acc
+ ''
127.0.0.1 ${host}
::1 ${host}
''
) "" subdomains;
};
virtualisation.podman.enable = true;
-1
View File
@@ -33,6 +33,5 @@ in
tuxcord-ca = mkSystem "tuxcord-ca" "x86_64-linux";
tuxcord-test = mkSystem "tuxcord-test" "x86_64-linux";
tuxcord-acmetest = mkSystem "tuxcord-acmetest" "x86_64-linux";
};
}
+1 -4
View File
@@ -15,10 +15,7 @@
"xhci_pci"
];
kernelModules = [
"kvm-amd"
"kvm-intel"
];
kernelModules = [ "kvm-intel" ];
};
hardware = {
-14
View File
@@ -1,14 +0,0 @@
{
imports = [
./storage.nix
];
networking.fqdn = "nix.tuxcord.net";
acme.rfc2136.nameserver = "tuxcord.net";
dns.enable = true;
services.getty.autologinUser = "root";
time.timeZone = "Europe/Madrid";
}
-6
View File
@@ -1,6 +0,0 @@
{
fileSystems."/" = {
device = "/dev/vda";
fsType = "ext4";
};
}
-6
View File
@@ -4,13 +4,7 @@
./storage.nix
];
acme = {
enable = true;
useSelfDns = true;
};
dns.enable = true;
networking.fqdn = "tuxcord.net";
time.timeZone = "Canada/Eastern";
}
-1
View File
@@ -32,7 +32,6 @@
device = "/dev/xvda2";
fsType = "btrfs";
options = [ "subvol=@persist" ] ++ defaultOptions;
neededForBoot = true;
};
};
}
+1 -9
View File
@@ -1,12 +1,4 @@
{
imports = [
./storage.nix
];
networking.fqdn = "tuxcord.test";
acme.enable = false;
dns.enable = true;
services.getty.autologinUser = "root";
networking.fqdn = "tuxcord.test";
}
-6
View File
@@ -1,6 +0,0 @@
{
fileSystems."/" = {
device = "/dev/vda";
fsType = "ext4";
};
}
+6
View File
@@ -55,6 +55,8 @@
};
};
fileSystems."/persist".neededForBoot = true;
environment.persistence."/persist" = {
enable = true;
hideMounts = true;
@@ -70,6 +72,10 @@
];
files = [
"/etc/machine-id"
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
"/etc/ssh/ssh_host_rsa_key"
"/etc/ssh/ssh_host_rsa_key.pub"
];
};
-89
View File
@@ -1,89 +0,0 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.acme;
inherit (lib)
mkIf
mkEnableOption
mkOption
types
;
inherit (config.networking) fqdn;
in
{
# we'll only support rfc2136 based challenges
options.acme = {
enable = mkEnableOption "" // {
default = true;
};
useSelfDns = mkOption {
default = false;
description = "Sets values of the self DNS if enabled, otherwise requires manual `rfc2136` nameserver and key values.";
};
rfc2136 = {
key = mkOption {
type = types.path;
default = config.age.secrets."dns/${fqdn}.key.age".path;
};
nameserver = mkOption {
type = types.str;
default = if cfg.useSelfDns then fqdn else null;
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = with cfg.rfc2136; nameserver != null && key != null;
message = "ACME needs rfc2136 parameters to work, consider using `useSelfDns` option.";
}
];
environment.persistence."/persist".directories = [
{
directory = "/var/lib/acme";
group = "acme";
user = "acme";
}
];
security.acme = {
acceptTerms = true;
defaults = {
email = "error@tuxcord.net";
reloadServices = [ "nginx" ];
postRun = ''
source ${config.age.secrets.ntfy.path}
${pkgs.ntfy-sh}/bin/ntfy publish -T recycle -t "${config.host.name}" "HTTPS certificate has been renewed"
'';
};
certs."${fqdn}" = {
dnsProvider = "rfc2136";
environmentFile =
with cfg.rfc2136;
builtins.toFile "dns-01-challenge.cfg" ''
RFC2136_NAMESERVER=${nameserver}
RFC2136_TSIG_FILE="${key}"
'';
extraDomainNames = [
"*.${fqdn}"
"${fqdn}"
];
inherit (config.services.nginx) group;
};
};
};
}
+1 -2
View File
@@ -1,9 +1,8 @@
{
imports = [
./acme.nix
./dns.nix
./fail2ban.nix
./forgejo.nix
./gitea.nix
./host.nix
./nginx.nix
./snapper.nix
+32 -34
View File
@@ -1,21 +1,6 @@
{
config,
lib,
self,
...
}:
{ config, lib, ... }:
let
cfg = config.dns;
inherit (lib)
mkEnableOption
mkIf
strings
;
inherit (config.networking) fqdn;
agenixDnsDir = "${self}/agenix/dns/${fqdn}";
agenixDnsDir = ../../agenix/dns + "/${config.dns.domain}";
agenixKeys = builtins.attrNames (builtins.readDir agenixDnsDir);
keys = map (
@@ -25,23 +10,35 @@ let
subdomain = name: "subdomain ${name}";
zoneDomain =
if strings.hasSuffix ".key.age" filename then
strings.removeSuffix ".key.age" filename
if lib.strings.hasSuffix ".key.age" filename then
lib.strings.removeSuffix ".key.age" filename
else
throw "${filename} is not a `.key.age` file";
in
{
inherit (config.age.secrets."dns/${filename}") path;
name = zoneDomain;
type = if zoneDomain == fqdn then zonesub else subdomain;
path = config.age.secrets."dns/${filename}".path;
type = if zoneDomain == config.dns.domain then zonesub else subdomain;
}
) agenixKeys;
cfg = config.dns;
inherit (lib)
mkEnableOption
mkOption
mkIf
;
in
{
options.dns = {
enable = mkEnableOption "" // {
default = true;
};
domain = mkOption {
type = with lib.types; str;
default = config.networking.fqdn;
};
};
config = mkIf cfg.enable {
@@ -56,8 +53,7 @@ in
value = {
file = path;
group = "named";
owner = if config.acme.enable then "acme" else "named";
mode = "440";
owner = "named";
};
}
) agenixKeys
@@ -68,17 +64,19 @@ in
extraConfig = builtins.concatStringsSep "\n" (map (key: "include \"${key.path}\";") keys);
zones."${fqdn}" = {
# grant "tuxcord.net" zonesub ANY;
extraConfig = ''
update-policy {
${builtins.concatStringsSep "\n" (
map (key: "grant \"${key.name}\" ${key.type key.name} ANY;") keys
)}
};
'';
file = "/var/dns/${fqdn}.zone"; # need to put default stuff
master = true;
zones = {
"${config.dns.domain}" = {
# grant "tuxcord.net" zonesub ANY;
extraConfig = ''
update-policy {
${builtins.concatStringsSep "\n" (
map (key: "grant \"${key.name}\" ${key.type key.name} ANY;") keys
)}
};
'';
file = "/var/dns/${config.dns.domain}.zone"; # need to put default stuff
master = true;
};
};
};
-125
View File
@@ -1,125 +0,0 @@
{ config, pkgs, ... }:
let
inherit (config.networking) fqdn;
acmeEnabled = config.acme.enable;
themeName = "tuxcord";
forgejoPublic = pkgs.linkFarm "forgejo-public" [
{
name = "assets/css/theme-${themeName}.css";
path = ../../assets/forgejo/theme.css;
}
{
name = "assets/img";
path = makeForgejoImages {
big = ../../assets/branding/logo.svg;
small = ../../assets/branding/logo-head.svg;
rasterWidth = 1024;
};
}
{
name = "assets/images/full-logo.svg";
path = ../../assets/branding/logo.svg;
}
];
forgejoTemplates = ../../assets/forgejo/templates;
makeForgejoImages =
{
big,
small,
rasterWidth,
}:
pkgs.stdenv.mkDerivation rec {
name = "forgejo-images";
srcs = [
big
small
];
unpackPhase = "true";
buildInputs = with pkgs; [
inkscape
];
# https://forgejo.org/docs/next/contributor/customization/#changing-the-logo
buildPhase = ''
mkdir -p $out
cp "${big}" $out/logo.svg
inkscape -w ${toString rasterWidth} ${big} -o $out/logo.png
cp "${small}" $out/favicon.svg
inkscape -w ${toString rasterWidth} ${small} -o $out/favicon.png
'';
};
in
{
services.forgejo = {
enable = true;
database.type = "mysql";
lfs.enable = true;
settings = {
DEFAULT = {
APP_NAME = "TuxCord Code Forge";
};
server = {
DOMAIN = fqdn;
ROOT_URL = "${if acmeEnabled then "https" else "http"}://${fqdn}/";
HTTP_PORT = 3000;
};
service = {
DISABLE_REGISTRATION = true;
REQUIRE_SIGNIN_VIEW = false;
};
repository = {
ENABLE_PUSH_CREATE_USER = true;
ENABLE_PUSH_CREATE_ORG = true;
DEFAULT_BRANCH = "main";
};
ui = {
DEFAULT_THEME = themeName;
};
# TODO: once we have email setup this would be nice
mailer.ENABLED = true;
actions = {
ENABLED = true;
# DEFAULT_ACTIONS_URL = "github";
};
};
};
systemd.services.forgejo-branding = {
enable = true;
wantedBy = [ "forgejo.service" ];
before = [ "forgejo.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = pkgs.writeShellScript "forgejo-branding.oneshot" ''
${pkgs.rsync}/bin/rsync -rl --chown forgejo:forgejo --delete ${forgejoPublic}/ ${config.services.forgejo.customDir}/public
${pkgs.rsync}/bin/rsync -rl --chown forgejo:forgejo --delete ${forgejoTemplates}/ ${config.services.forgejo.customDir}/templates
'';
};
};
environment.persistence."/persist".directories = [
{
directory = config.services.forgejo.stateDir;
group = "forgejo";
user = "forgejo";
}
];
}
+27
View File
@@ -0,0 +1,27 @@
{ config, lib, ... }:
{
services.gitea = {
enable = true;
appName = "Tuxcord's Gitea";
database.type = "mysql";
lfs.enable = true;
settings.server.DOMAIN = config.networking.fqdn;
# settings.server.ROOT_URL = "https://git.tuxcord.net/"; ? would also depend on ssl status
settings.server.HTTP_PORT = 3000;
settings.service.DISABLE_REGISTRATION = true;
settings.service.REQUIRE_SIGNIN_VIEW = false;
settings.repository.ENABLE_PUSH_CREATE_USER = true;
settings.repository.ENABLE_PUSH_CREATE_ORG = true;
settings.repository.DEFAULT_BRANCH = "main";
# settings.ui.DEFAULT_THEME = "...";
# TODO: once we have email setup this would be nice
settings.mailer.ENABLED = true;
};
}
+10 -39
View File
@@ -1,46 +1,17 @@
{ config, self, ... }:
{ config, ... }:
let
inherit (config.networking) fqdn;
mkVhost =
attrs: locations:
let
acmeEnabled = config.acme.enable;
in
attrs:
{
forceSSL = acmeEnabled;
useACMEHost = if acmeEnabled then fqdn else null;
locations = {
"= /robots.txt" = {
alias = disallowedRobotsTxt;
};
}
// locations;
forceSSL = false; # TODO: tweak per host
}
// attrs;
mkProxy = port: {
proxyPass = "http://127.0.0.1:${toString port}/";
extraConfig = ''
proxy_buffering off;
proxy_request_buffering off;
'';
};
mkSsi = webRoot: {
root = webRoot;
extraConfig = ''
ssi on;
'';
};
disallowedRobotsTxt = builtins.toFile "robots.txt" ''
User-agent: *
Disallow: /
'';
in
{
services.nginx = {
@@ -52,14 +23,14 @@ in
recommendedGzipSettings = true;
recommendedOptimisation = true;
virtualHosts = {
"${fqdn}" = mkVhost { default = true; } {
"/" = mkSsi "${self.pins.website}/web-root";
};
# services.nginx.virtualHosts."${fqdn}" = {
# addSSL = true;
# root = "/var/www/myhost.org";
# default = true;
# };
"git.${fqdn}" = mkVhost { } {
"/" = mkProxy config.services.forgejo.settings.server.HTTP_PORT;
};
virtualHosts."git.${fqdn}" = mkVhost {
locations."/" = mkProxy config.services.gitea.settings.server.HTTP_PORT;
};
};
+9 -3
View File
@@ -1,17 +1,23 @@
{ config, ... }:
{
services.openssh = {
enable = true;
settings = {
ClientAliveInterval = 300;
X11Forwarding = true;
KbdInteractiveAuthentication = false;
PasswordAuthentication = false;
PermitRootLogin = "no";
};
};
<<<<<<< HEAD
networking.firewall.allowedTCPPorts = config.services.openssh.ports;
networking.firewall.allowedTCPPorts = [ 22 ];
||||||| parent of 1c2f11d (lib/ssh: add more ssh keys)
users.users.root.openssh.authorizedKeys.keys = builtins.attrValues {
inherit (import "${self}/lib/ssh/keys.nix") error javalsai;
};
=======
>>>>>>> 1c2f11d (lib/ssh: add more ssh keys)
}
+60 -36
View File
@@ -1,6 +1,25 @@
{ lib, self, ... }:
let
inherit (self.lib) users;
users = [
{
name = "error";
options.admin = true;
}
{
name = "javalsai";
options.admin = true;
}
{
name = "max";
options.admin = true;
}
{
name = "vectorum";
}
{
name = "pickzelle";
}
];
adminGroups = [
"adm"
@@ -11,55 +30,60 @@ let
"wheel"
];
mkUser = name: uid: admin: {
users.users.${name} = {
inherit uid;
isNormalUser = true;
extraGroups = lib.optionals admin adminGroups;
openssh.authorizedKeys.keys = self.lib.getSSHKeys name;
};
getSSHKeys =
username:
let
sshKeys = import "${self}/lib/ssh/keys.nix";
in
if (builtins.hasAttr username sshKeys) then
lib.lists.toList sshKeys.${username}
else
lib.warn "user ${username} declared without ssh key" [ ];
systemd.slices."user-${builtins.toString uid}".sliceConfig = {
CPUQuota = "50%";
CPUWeight = "10";
IOAccounting = true;
IOWeight = "10";
MemoryMax = "2G";
MemorySwapMax = "1G";
TasksMax = "100";
mkUser =
name: uid: options:
let
admin = options.admin or false;
in
{
users.users.${name} = {
isNormalUser = true;
extraGroups = lib.optionals admin adminGroups;
inherit uid;
openssh.authorizedKeys.keys = getSSHKeys name;
};
systemd.slices."user-${builtins.toString uid}".sliceConfig = {
CPUQuota = "50%";
CPUWeight = "10";
IOAccounting = true;
IOWeight = "10";
MemoryMax = "2G";
MemorySwapMax = "1G";
TasksMax = "100";
};
};
};
in
lib.recursiveUpdate
(builtins.foldl'
(attrs: user: {
options = lib.recursiveUpdate attrs.options (
mkUser user.name attrs.uid (user.value.admin or false)
);
options = lib.recursiveUpdate attrs.options (mkUser user.name attrs.uid (user.options or { }));
uid = attrs.uid + 1;
})
{
options = { };
uid = 1000;
}
(lib.attrsToList users)
users
).options
{
users = {
motd = ''
__ __ __
---------/\ \__ /\ \ /\ \__
---------\ \ ,_\ __ __ __ _ ___ ___ _ __ \_\ \ ___ __\ \ ,_\
----------\ \ \/ /\ \/\ \/\ \/'\ /'___\ / __`\/\`'__\/'_` \ /'_ `\ /'__`\ \ \/
-----------\ \ \_\ \ \_\ \/> <//\ \__//\ \L\ \ \ \//\ \L\ \ __/\ \/\ \/\ __/\ \ \_
------------\ \__\\ \____//\_/\_\ \____\ \____/\ \_\\ \___,_\/\_\ \_\ \_\ \____\\ \__\
-------------\/__/ \/___/ \//\/_/\/____/\/___/ \/_/ \/__,_ /\/_/\/_/\/_/\/____/ \/__/
A friendly Linux community - est. July 2023
'';
users.users.root = {
initialPassword = "tuxcord";
users.root = {
initialPassword = "tuxcord";
openssh.authorizedKeys.keys = self.lib.adminSSHKeys;
};
openssh.authorizedKeys.keys = lib.lists.concatLists (
map (user: getSSHKeys user.name) (builtins.filter (user: user.options.admin or false) users)
);
};
}
-259
View File
@@ -1,259 +0,0 @@
/*
This file is provided under the MIT licence:
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 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.
*/
# Generated by npins. Do not modify; will be overwritten regularly
let
# Backwards-compatibly make something that previously didn't take any arguments take some
# The function must return an attrset, and will unfortunately be eagerly evaluated
# Same thing, but it catches eval errors on the default argument so that one may still call it with other arguments
mkFunctor =
fn:
let
e = builtins.tryEval (fn { });
in
(if e.success then e.value else { error = fn { }; }) // { __functor = _self: fn; };
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
range =
first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
concatStrings = builtins.concatStringsSep "";
# If the environment variable NPINS_OVERRIDE_${name} is set, then use
# the path directly as opposed to the fetched source.
# (Taken from Niv for compatibility)
mayOverride =
name: path:
let
envVarName = "NPINS_OVERRIDE_${saneName}";
saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name;
ersatz = builtins.getEnv envVarName;
in
if ersatz == "" then
path
else
# this turns the string into an actual Nix path (for both absolute and
# relative paths)
builtins.trace "Overriding path of \"${name}\" with \"${ersatz}\" due to set \"${envVarName}\"" (
if builtins.substring 0 1 ersatz == "/" then
/. + ersatz
else
/. + builtins.getEnv "PWD" + "/${ersatz}"
);
mkSource =
name: spec:
{
pkgs ? null,
}:
assert spec ? type;
let
# Unify across builtin and pkgs fetchers.
# `fetchGit` requires a wrapper because of slight API differences.
fetchers =
if pkgs == null then
{
inherit (builtins) fetchTarball fetchurl;
# Frustratingly, due to flakes and `fetchTree`, `fetchGit`
# has a different signature than the other builtin
# fetchers
fetchGit = args: (builtins.fetchGit args).outPath;
}
else
{
fetchTarball =
{
url,
sha256,
}:
pkgs.fetchzip {
inherit url sha256;
extension = "tar";
};
inherit (pkgs) fetchurl;
fetchGit =
{
url,
submodules,
rev,
name,
lfs,
narHash,
}:
pkgs.fetchgit {
inherit url rev name lfs;
fetchSubmodules = submodules;
hash = narHash;
};
};
path =
if spec.type == "Git" then
mkGitSource fetchers spec
else if spec.type == "GitRelease" then
mkGitSource fetchers spec
else if spec.type == "PyPi" then
mkPyPiSource fetchers spec
else if spec.type == "Channel" then
mkChannelSource fetchers spec
else if spec.type == "Url" || spec.type == "MutableUrl" then
mkUrlSource fetchers spec
else if spec.type == "Container" then
mkContainerSource pkgs spec
else
builtins.throw "Unknown source type ${spec.type}";
in
spec // { outPath = mayOverride name path; };
mkGitSource =
{
fetchTarball,
fetchGit,
...
}:
{
repository,
revision,
url ? null,
submodules,
hash,
lfs,
...
}:
assert repository ? type;
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
# In the latter case, there we will always be an url to the tarball
if url != null && !submodules then
fetchTarball {
inherit url;
sha256 = hash;
}
else
let
url =
if repository.type == "Git" then
repository.url
else if repository.type == "GitHub" then
"https://github.com/${repository.owner}/${repository.repo}.git"
else if repository.type == "GitLab" then
"${repository.server}/${repository.repo_path}.git"
else if repository.type == "Forgejo" then
"${repository.server}/${repository.owner}/${repository.repo}.git"
else
throw "Unrecognized repository type ${repository.type}";
urlToName =
url: rev:
let
matched = builtins.match "^.*/([^/]*)(\\.git)?$" url;
short = builtins.substring 0 7 rev;
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
in
"${if matched == null then "source" else builtins.head matched}${appendShort}";
name = urlToName url revision;
in
fetchGit {
rev = revision;
narHash = hash;
inherit name submodules url lfs;
};
mkPyPiSource =
{ fetchurl, ... }:
{
url,
hash,
...
}:
fetchurl {
inherit url;
sha256 = hash;
};
mkChannelSource =
{ fetchTarball, ... }:
{
url,
hash,
...
}:
fetchTarball {
inherit url;
sha256 = hash;
};
mkUrlSource =
{
fetchTarball,
fetchurl,
...
}:
{
url,
hash,
unpack,
...
}:
(if unpack then fetchTarball else fetchurl) {
inherit url;
sha256 = hash;
};
mkContainerSource =
pkgs:
{
image_name,
image_tag,
image_digest,
hash,
...
}:
if pkgs == null then
builtins.throw "container sources require passing in a Nixpkgs value: https://github.com/andir/npins/blob/master/README.md#using-the-nixpkgs-fetchers"
else
pkgs.dockerTools.pullImage {
imageName = image_name;
imageDigest = image_digest;
finalImageTag = image_tag;
hash = hash;
};
in
mkFunctor (
{
input ? ./sources.json,
}:
let
data =
if builtins.isPath input then
# while `readFile` will throw an error anyways if the path doesn't exist,
# we still need to check beforehand because *our* error can be caught but not the one from the builtin
# See: <https://git.lix.systems/lix-project/lix/issues/1098>
if builtins.pathExists input then
builtins.fromJSON (builtins.readFile input)
else
throw "Input path ${toString input} does not exist"
else if builtins.isAttrs input then
input
else
throw "Unsupported input type ${builtins.typeOf input}, must be a path or an attrset";
version = data.version;
in
if version == 8 then
builtins.mapAttrs (name: spec: mkFunctor (mkSource name spec)) data.pins
else
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
)
-18
View File
@@ -1,18 +0,0 @@
{
"pins": {
"website": {
"type": "Git",
"repository": {
"type": "Git",
"url": "https://git.javalsai.tuxcord.net/tuxcord/website.git"
},
"branch": "main",
"submodules": false,
"lfs": true,
"revision": "b18dd7b863644debb0a843a5b21bb490bfe7d048",
"url": null,
"hash": "sha256-xYH9RXYZDVotUW8fKIEC9u0GJeEg2nV/23aQlEyeQso="
}
},
"version": 8
}
+2 -21
View File
@@ -2,26 +2,6 @@
{
perSystem =
{ pkgs, ... }:
let
npins' = pkgs.npins.overrideAttrs (
final: old: {
src = pkgs.fetchFromGitHub {
owner = "javalsai";
repo = "npins";
rev = "f3def7dfeecc16884cb0601f6c904d5142f47383";
hash = "sha256-ejeOGmDw+D4KddFJ5OAPradqoS+p2eAhhS4fOLQOWOk=";
};
cargoHash = null;
cargoDeps = pkgs.rustPlatform.fetchCargoVendor {
src = final.src;
hash = "sha256-mG4UClFBgiWBraWQ12N3CSyapaIpuXI9F8wQGwh/ooQ=";
};
cargoBuildFeatures = [ ];
}
);
in
{
devShells.default = pkgs.mkShell {
name = "configuration.nix";
@@ -51,9 +31,10 @@
git
inputs.agenix.packages.${stdenv.hostPlatform.system}.default
jujutsu
neovim
nix-output-monitor
nixfmt
npins'
npins
parted
smartmontools
statix