Compare commits

..

7 commits

Author SHA1 Message Date
5cb6f03e4e
try and recreate the container from icewind
see:
https://icewind.nl/entry/gitea-actions-nix/#using-nix-to-build-our-nix-image

> Error: crun: cannot find `` in $PATH: No such file or directory: OCI
runtime attempted to invoke a command that was not found
2025-07-02 21:05:44 +02:00
3e8c0c7738
runs-on: docker 2025-07-02 18:47:35 +02:00
6143e4545b
rm runner file 2025-07-02 18:47:35 +02:00
d062c5a21b
explicitly specify container image 2025-07-02 18:47:35 +02:00
abf62856d7
add label for new runner 2025-07-02 18:47:35 +02:00
14600ee06e
try out existing nix container made for gitea actions 2025-07-02 18:47:35 +02:00
0c53b55106
Switch all CI jobs to nixos label 2025-07-02 18:47:35 +02:00
60 changed files with 696 additions and 880 deletions

View file

@ -1,24 +0,0 @@
name: deploy-infra
on:
workflow_dispatch: # allows manual triggering
push:
branches:
- main
jobs:
deploy:
runs-on: native
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up SSH key for age secrets and SSH
run: |
env
mkdir -p ~/.ssh
echo "${{ secrets.CD_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
- name: Deploy
run: nix-shell --run 'eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519 && SHELL=$(which bash) nixops4 apply -v default'

View file

@ -10,49 +10,57 @@ on:
jobs: jobs:
check-pre-commit: check-pre-commit:
runs-on: native runs-on: docker
container:
image: icewind1991/nix-runner
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix-build -A tests - run: nix-build -A tests
check-data-model: check-data-model:
runs-on: native runs-on: docker
container:
image: icewind1991/nix-runner
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix-shell --run 'nix-unit ./deployment/data-model-test.nix' - run: nix-shell --run 'nix-unit ./deployment/data-model-test.nix'
check-mastodon:
runs-on: native
steps:
- uses: actions/checkout@v4
- run: nix build .#checks.x86_64-linux.test-mastodon-service -L
check-peertube: check-peertube:
runs-on: native runs-on: docker
container:
image: icewind1991/nix-runner
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix build .#checks.x86_64-linux.test-peertube-service -L - run: nix-build services -A tests.peertube
check-panel: check-panel:
runs-on: native runs-on: docker
container:
image: icewind1991/nix-runner
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix-build -A tests.panel - run: nix-build panel -A tests
check-deployment-basic: check-deployment-basic:
runs-on: native runs-on: docker
container:
image: icewind1991/nix-runner
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix build .#checks.x86_64-linux.deployment-basic -L - run: nix build .#checks.x86_64-linux.deployment-basic -L
check-deployment-cli: check-deployment-cli:
runs-on: native runs-on: docker
container:
image: icewind1991/nix-runner
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix build .#checks.x86_64-linux.deployment-cli -L - run: nix build .#checks.x86_64-linux.deployment-cli -L
check-deployment-panel: check-deployment-panel:
runs-on: native runs-on: docker
container:
image: icewind1991/nix-runner
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix build .#checks.x86_64-linux.deployment-panel -L - run: nix build .#checks.x86_64-linux.deployment-panel -L

View file

@ -8,16 +8,15 @@ on:
jobs: jobs:
lockfile: lockfile:
runs-on: native runs-on: nix
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Update pins - name: Update pins
run: nix-shell --run "npins update" run: nix-shell --run "npins update"
- name: Create PR - name: Create PR
uses: https://github.com/KiaraGrouwstra/gitea-create-pull-request@f9f80aa5134bc5c03c38f5aaa95053492885b397 uses: peter-evans/create-pull-request@v7
with: with:
remote-instance-api-version: v1
token: "${{ secrets.DEPLOY_KEY }}" token: "${{ secrets.DEPLOY_KEY }}"
branch: npins-update branch: npins-update
commit-message: "npins: update sources" commit-message: "npins: update sources"

View file

@ -12,7 +12,6 @@ let
inherit (pkgs) lib; inherit (pkgs) lib;
inherit (import sources.flake-inputs) import-flake; inherit (import sources.flake-inputs) import-flake;
inherit ((import-flake { src = ./.; }).inputs) nixops4; inherit ((import-flake { src = ./.; }).inputs) nixops4;
panel = import ./panel { inherit sources system; };
pre-commit-check = pre-commit-check =
(import "${git-hooks}/nix" { (import "${git-hooks}/nix" {
inherit nixpkgs system; inherit nixpkgs system;
@ -72,7 +71,6 @@ in
tests = { tests = {
inherit pre-commit-check; inherit pre-commit-check;
panel = panel.tests;
}; };
# re-export inputs so they can be overridden granularly # re-export inputs so they can be overridden granularly

View file

@ -1,8 +0,0 @@
{
targetMachines = [
"hello"
"cowsay"
];
pathToRoot = ../../..;
pathFromRoot = ./.;
}

View file

@ -1,14 +0,0 @@
{
runNixOSTest,
inputs,
sources,
}:
runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot;
}

View file

@ -1,36 +0,0 @@
{
inputs,
sources,
lib,
providers,
...
}:
let
inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot;
in
{
providers = {
inherit (inputs.nixops4.modules.nixops4Provider) local;
};
resources = lib.genAttrs targetMachines (nodeName: {
type = providers.local.exec;
imports = [
inputs.nixops4-nixos.modules.nixops4Resource.nixos
../common/targetResource.nix
];
_module.args = { inherit inputs sources; };
inherit nodeName pathToRoot pathFromRoot;
nixos.module =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.${nodeName} ];
};
});
}

View file

@ -0,0 +1,57 @@
{
self,
inputs,
lib,
sources,
...
}:
let
inherit (lib) genAttrs;
targetMachines = [
"hello"
"cowsay"
];
pathToRoot = /. + (builtins.unsafeDiscardStringContext self);
pathFromRoot = ./.;
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
checks.deployment-basic = pkgs.testers.runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit targetMachines pathToRoot pathFromRoot;
};
};
nixops4Deployments.check-deployment-basic =
{ providers, ... }:
{
providers = {
inherit (inputs.nixops4.modules.nixops4Provider) local;
};
resources = genAttrs targetMachines (nodeName: {
type = providers.local.exec;
imports = [
inputs.nixops4-nixos.modules.nixops4Resource.nixos
../common/targetResource.nix
];
_module.args = { inherit inputs sources; };
inherit nodeName pathToRoot pathFromRoot;
nixos.module =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.${nodeName} ];
};
});
};
}

View file

@ -1,22 +0,0 @@
{
inputs = {
nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos";
};
outputs =
inputs:
import ./mkFlake.nix inputs (
{ inputs, sources, ... }:
{
imports = [
inputs.nixops4.modules.flake.default
];
nixops4Deployments.check-deployment-basic = {
imports = [ ./deployment/check/basic/deployment.nix ];
_module.args = { inherit inputs sources; };
};
}
);
}

View file

@ -1,15 +1,10 @@
{ inputs, lib, ... }: { inputs, ... }:
{ {
_class = "nixosTest"; _class = "nixosTest";
name = "deployment-basic"; name = "deployment-basic";
sourceFileset = lib.fileset.unions [
./constants.nix
./deployment.nix
];
nodes.deployer = nodes.deployer =
{ pkgs, ... }: { pkgs, ... }:
{ {

View file

@ -1,11 +0,0 @@
{
targetMachines = [
"garage"
"mastodon"
"peertube"
"pixelfed"
];
pathToRoot = ../../..;
pathFromRoot = ./.;
enableAcme = true;
}

View file

@ -1,19 +0,0 @@
{
runNixOSTest,
inputs,
sources,
}:
runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
}

View file

@ -1,59 +0,0 @@
{
inputs,
sources,
lib,
}:
let
inherit (builtins) fromJSON readFile listToAttrs;
inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot
pathFromRoot
enableAcme
;
};
## The deployment function - what we are here to test!
##
## TODO: Modularise `deployment/default.nix` to get rid of the nested
## function calls.
makeTestDeployment =
args:
(import ../..)
{
inherit lib;
inherit (inputs) nixops4 nixops4-nixos;
fediversity = import ../../../services/fediversity;
}
(listToAttrs (
map (nodeName: {
name = "${nodeName}ConfigurationResource";
value = makeTargetResource nodeName;
}) targetMachines
))
(fromJSON (readFile ../../configuration.sample.json) // args);
in
{
check-deployment-cli-nothing = makeTestDeployment { };
check-deployment-cli-mastodon-pixelfed = makeTestDeployment {
mastodon.enable = true;
pixelfed.enable = true;
};
check-deployment-cli-peertube = makeTestDeployment {
peertube.enable = true;
};
}

View file

@ -0,0 +1,90 @@
{
self,
inputs,
lib,
sources,
...
}:
let
inherit (builtins) fromJSON readFile listToAttrs;
targetMachines = [
"garage"
"mastodon"
"peertube"
"pixelfed"
];
pathToRoot = /. + (builtins.unsafeDiscardStringContext self);
pathFromRoot = ./.;
enableAcme = true;
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
checks.deployment-cli = pkgs.testers.runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
};
};
nixops4Deployments =
let
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot
pathFromRoot
enableAcme
;
};
## The deployment function - what we are here to test!
##
## TODO: Modularise `deployment/default.nix` to get rid of the nested
## function calls.
makeTestDeployment =
args:
(import ../..)
{
inherit lib;
inherit (inputs) nixops4 nixops4-nixos;
fediversity = import ../../../services/fediversity;
}
(listToAttrs (
map (nodeName: {
name = "${nodeName}ConfigurationResource";
value = makeTargetResource nodeName;
}) targetMachines
))
(fromJSON (readFile ../../configuration.sample.json) // args);
in
{
check-deployment-cli-nothing = makeTestDeployment { };
check-deployment-cli-mastodon-pixelfed = makeTestDeployment {
mastodon.enable = true;
pixelfed.enable = true;
};
check-deployment-cli-peertube = makeTestDeployment {
peertube.enable = true;
};
};
}

View file

@ -1,26 +0,0 @@
{
inputs = {
nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos";
};
outputs =
inputs:
import ./mkFlake.nix inputs (
{
inputs,
sources,
lib,
...
}:
{
imports = [
inputs.nixops4.modules.flake.default
];
nixops4Deployments = import ./deployment/check/cli/deployments.nix {
inherit inputs sources lib;
};
}
);
}

View file

@ -1,9 +1,4 @@
{ { inputs, hostPkgs, ... }:
inputs,
hostPkgs,
lib,
...
}:
let let
## Some places need a dummy file that will in fact never be used. We create ## Some places need a dummy file that will in fact never be used. We create
@ -16,21 +11,6 @@ in
name = "deployment-cli"; name = "deployment-cli";
sourceFileset = lib.fileset.unions [
./constants.nix
./deployments.nix
# REVIEW: I would like to be able to grab all of `/deployment` minus
# `/deployment/check`, but I can't because there is a bunch of other files
# in `/deployment`. Maybe we can think of a reorg making things more robust
# here? (comment also in panel test)
../../default.nix
../../options.nix
../../configuration.sample.json
../../../services/fediversity
];
nodes.deployer = nodes.deployer =
{ pkgs, ... }: { pkgs, ... }:
{ {

View file

@ -54,13 +54,13 @@ in
system.extraDependencies = system.extraDependencies =
[ [
inputs.nixops4 "${inputs.flake-parts}"
inputs.nixops4-nixos "${inputs.flake-parts.inputs.nixpkgs-lib}"
inputs.nixpkgs "${inputs.nixops4}"
"${inputs.nixops4-nixos}"
"${inputs.nixpkgs}"
sources.flake-parts "${sources.flake-inputs}"
sources.flake-inputs
sources.git-hooks
pkgs.stdenv pkgs.stdenv
pkgs.stdenvNoCC pkgs.stdenvNoCC

View file

@ -13,7 +13,6 @@ let
toJSON toJSON
; ;
inherit (lib) inherit (lib)
types
fileset fileset
mkOption mkOption
genAttrs genAttrs
@ -28,6 +27,14 @@ let
forConcat = xs: f: concatStringsSep "\n" (map f xs); forConcat = xs: f: concatStringsSep "\n" (map f xs);
## The whole repository, with the flake at its root.
## FIXME: We could probably have fileset be the union of ./. with flake.nix
## and flake.lock - I doubt we need anything else.
src = fileset.toSource {
fileset = config.pathToRoot;
root = config.pathToRoot;
};
## We will need to override some inputs by the empty flake, so we make one. ## We will need to override some inputs by the empty flake, so we make one.
emptyFlake = runCommandNoCC "empty-flake" { } '' emptyFlake = runCommandNoCC "empty-flake" { } ''
mkdir $out mkdir $out
@ -46,39 +53,9 @@ in
## FIXME: I wish I could just use `testScript` but with something like ## FIXME: I wish I could just use `testScript` but with something like
## `mkOrder` to put this module's string before something else. ## `mkOrder` to put this module's string before something else.
extraTestScript = mkOption { }; extraTestScript = mkOption { };
sourceFileset = mkOption {
## REVIEW: Upstream to nixpkgs?
type = types.mkOptionType {
name = "fileset";
description = "fileset";
descriptionClass = "noun";
check = (x: (builtins.tryEval (fileset.unions [ x ])).success);
merge = (_: defs: fileset.unions (map (x: x.value) defs));
};
description = ''
A fileset that will be copied to the deployer node in the current
working directory. This should contain all the files that are
necessary to run that particular test, such as the NixOS
modules necessary to evaluate a deployment.
'';
};
}; };
config = { config = {
sourceFileset = fileset.unions [
# NOTE: not the flake itself; it will be overridden.
../../../mkFlake.nix
../../../flake.lock
../../../npins
./sharedOptions.nix
./targetNode.nix
./targetResource.nix
(config.pathToCwd + "/flake-under-test.nix")
];
acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; acmeNodeIP = config.nodes.acme.networking.primaryIPAddress;
nodes = nodes =
@ -126,16 +103,8 @@ in
${n}.wait_for_unit("multi-user.target") ${n}.wait_for_unit("multi-user.target")
'')} '')}
## A subset of the repository that is necessary for this test. It will be
## copied inside the test. The smaller this set, the faster our CI, because we
## won't need to re-run when things change outside of it.
with subtest("Unpacking"): with subtest("Unpacking"):
deployer.succeed("cp -r --no-preserve=mode ${ deployer.succeed("cp -r --no-preserve=mode ${src}/* .")
fileset.toSource {
root = ../../..;
fileset = config.sourceFileset;
}
}/* .")
with subtest("Configure the network"): with subtest("Configure the network"):
${forConcat config.targetMachines ( ${forConcat config.targetMachines (
@ -165,16 +134,11 @@ in
## NOTE: This is super slow. It could probably be optimised in Nix, for ## NOTE: This is super slow. It could probably be optimised in Nix, for
## instance by allowing to grab things directly from the host's store. ## instance by allowing to grab things directly from the host's store.
## with subtest("Override the lock"):
## NOTE: We use the repository as-is (cf `src` above), overriding only
## `flake.nix` by our `flake-under-test.nix`. We also override the flake
## lock file to use locally available inputs, as we cannot download them.
##
with subtest("Override the flake and its lock"):
deployer.succeed("cp ${config.pathFromRoot}/flake-under-test.nix flake.nix")
deployer.succeed(""" deployer.succeed("""
nix flake lock --extra-experimental-features 'flakes nix-command' \ nix flake lock --extra-experimental-features 'flakes nix-command' \
--offline -v \ --offline -v \
--override-input flake-parts ${inputs.flake-parts} \
--override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \ --override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \
\ \
--override-input nixops4-nixos ${inputs.nixops4-nixos} \ --override-input nixops4-nixos ${inputs.nixops4-nixos} \
@ -186,6 +150,9 @@ in
inputs.nixops4-nixos.inputs.nixops4.packages.${system}.flake-in-a-bottle inputs.nixops4-nixos.inputs.nixops4.packages.${system}.flake-in-a-bottle
} \ } \
--override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \ --override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \
\
--override-input nixpkgs ${inputs.nixpkgs} \
--override-input git-hooks ${inputs.git-hooks} \
; ;
""") """)

View file

@ -1,11 +0,0 @@
{
targetMachines = [
"garage"
"mastodon"
"peertube"
"pixelfed"
];
pathToRoot = ../../..;
pathFromRoot = ./.;
enableAcme = true;
}

View file

@ -1,19 +0,0 @@
{
runNixOSTest,
inputs,
sources,
}:
runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
}

View file

@ -1,58 +0,0 @@
{
inputs,
sources,
lib,
}:
let
inherit (builtins) fromJSON listToAttrs;
inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot
pathFromRoot
enableAcme
;
};
## The deployment function - what we are here to test!
##
## TODO: Modularise `deployment/default.nix` to get rid of the nested
## function calls.
makeTestDeployment =
args:
(import ../..)
{
inherit lib;
inherit (inputs) nixops4 nixops4-nixos;
fediversity = import ../../../services/fediversity;
}
(listToAttrs (
map (nodeName: {
name = "${nodeName}ConfigurationResource";
value = makeTargetResource nodeName;
}) targetMachines
))
args;
in
makeTestDeployment (
fromJSON (
let
env = builtins.getEnv "DEPLOYMENT";
in
if env == "" then
throw "The DEPLOYMENT environment needs to be set. You do not want to use this deployment unless in the `deployment-panel` NixOS test."
else
env
)
)

View file

@ -0,0 +1,94 @@
{
self,
inputs,
lib,
sources,
...
}:
let
inherit (builtins)
fromJSON
listToAttrs
;
targetMachines = [
"garage"
"mastodon"
"peertube"
"pixelfed"
];
pathToRoot = /. + (builtins.unsafeDiscardStringContext self);
pathFromRoot = ./.;
enableAcme = true;
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
checks.deployment-panel = pkgs.testers.runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
};
};
nixops4Deployments =
let
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot
pathFromRoot
enableAcme
;
};
## The deployment function - what we are here to test!
##
## TODO: Modularise `deployment/default.nix` to get rid of the nested
## function calls.
makeTestDeployment =
args:
(import ../..)
{
inherit lib;
inherit (inputs) nixops4 nixops4-nixos;
fediversity = import ../../../services/fediversity;
}
(listToAttrs (
map (nodeName: {
name = "${nodeName}ConfigurationResource";
value = makeTargetResource nodeName;
}) targetMachines
))
args;
in
{
check-deployment-panel = makeTestDeployment (
fromJSON (
let
env = builtins.getEnv "DEPLOYMENT";
in
if env == "" then
throw "The DEPLOYMENT environment needs to be set. You do not want to use this deployment unless in the `deployment-panel` NixOS test."
else
env
)
);
};
}

View file

@ -1,26 +0,0 @@
{
inputs = {
nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos";
};
outputs =
inputs:
import ./mkFlake.nix inputs (
{
inputs,
sources,
lib,
...
}:
{
imports = [
inputs.nixops4.modules.flake.default
];
nixops4Deployments.check-deployment-panel = import ./deployment/check/panel/deployment.nix {
inherit inputs sources lib;
};
}
);
}

View file

@ -125,20 +125,6 @@ in
name = "deployment-panel"; name = "deployment-panel";
sourceFileset = lib.fileset.unions [
./constants.nix
./deployment.nix
# REVIEW: I would like to be able to grab all of `/deployment` minus
# `/deployment/check`, but I can't because there is a bunch of other files
# in `/deployment`. Maybe we can think of a reorg making things more robust
# here? (comment also in CLI test)
../../default.nix
../../options.nix
../../../services/fediversity
];
## The panel's module sets `nixpkgs.overlays` which clashes with ## The panel's module sets `nixpkgs.overlays` which clashes with
## `pkgsReadOnly`. We disable it here. ## `pkgsReadOnly`. We disable it here.
node.pkgsReadOnly = false; node.pkgsReadOnly = false;

View file

@ -1,13 +1,9 @@
let let
inherit (import ../default.nix { }) pkgs inputs; inherit (import ../default.nix { }) pkgs;
inherit (pkgs) lib; inherit (pkgs) lib;
inherit (lib) mkOption;
eval = eval =
module: module:
(lib.evalModules { (lib.evalModules {
specialArgs = {
inherit inputs;
};
modules = [ modules = [
module module
./data-model.nix ./data-model.nix
@ -20,51 +16,32 @@ in
test-eval = { test-eval = {
expr = expr =
let let
fediversity = eval ( example = eval {
{ config, ... }: runtime-environments.bar.nixos = {
{ module =
config = { { ... }:
applications.hello = {
{ ... }: system.stateVersion = "25.05";
{
description = ''Command-line tool that will print "Hello, world!" on the terminal'';
module =
{ ... }:
{
options = {
enable = lib.mkEnableOption "Hello in the shell";
};
};
implementation =
cfg:
lib.optionalAttrs cfg.enable {
dummy.login-shell.packages.hello = pkgs.hello;
};
};
};
options = {
example-configuration = mkOption {
type = config.configuration;
readOnly = true;
default = {
enable = true;
applications.hello.enable = true;
};
}; };
}; };
} applications.foo = {
); module =
{ pkgs, ... }:
{
environment.systemPackages = [
pkgs.hello
];
};
};
};
in in
{ {
inherit (fediversity) has-runtime = lib.isAttrs example.runtime-environments.bar.nixos.module;
example-configuration has-application = lib.isAttrs example.applications.foo.module;
;
}; };
expected = { expected = {
example-configuration = { has-runtime = true;
enable = true; has-application = true;
applications.hello.enable = true;
};
}; };
}; };
} }

View file

@ -1,89 +1,45 @@
{ {
lib, lib,
config,
... ...
}: }:
let let
inherit (lib) mkOption types; inherit (lib) types mkOption;
inherit (lib.types)
attrsOf
attrTag
deferredModuleWith
submodule
optionType
functionTo
;
functionType = import ./function.nix;
application-resources = {
options.resources = mkOption {
# TODO: maybe transpose, and group the resources by type instead
type = attrsOf (
attrTag (lib.mapAttrs (_name: resource: mkOption { type = resource.request; }) config.resources)
);
};
};
in in
with types;
{ {
_class = "nixops4Deployment"; _class = "nixops4Deployment";
options = { options = {
applications = mkOption { runtime-environments = mkOption {
description = "Collection of Fediversity applications"; description = "Collection of runtime environments into which applications can be deployed";
type = attrsOf ( type = attrsOf (attrTag {
submodule (application: { nixos = mkOption {
_class = "fediversity-application"; description = "A single NixOS machine";
options = { type = submodule {
description = mkOption { options = {
description = "Description to be shown in the application overview"; module = mkOption {
type = types.str; description = "The NixOS module describing the base configuration for that machine";
}; type = deferredModule;
module = mkOption {
description = "Operator-facing configuration options for the application";
type = deferredModuleWith { staticModules = [ { _class = "fediversity-application-config"; } ]; };
};
implementation = mkOption {
description = "Mapping of application configuration to deployment resources, a description of what an application needs to run";
type = application.config.config-mapping.function-type;
};
resources = mkOption {
description = "Compute resources required by an application";
type = functionTo application.config.config-mapping.output-type;
readOnly = true;
default = input: (application.config.implementation input).output;
};
config-mapping = mkOption {
description = "Function type for the mapping from application configuration to required resources";
type = submodule functionType;
readOnly = true;
default = {
input-type = application.config.module;
output-type = application-resources;
}; };
}; };
}; };
})
);
};
configuration = mkOption {
description = "Configuration type declaring options to be set by operators";
type = optionType;
readOnly = true;
default = submodule {
options = {
enable = lib.mkEnableOption {
description = "your Fediversity configuration";
};
applications = lib.mapAttrs (
_name: application:
mkOption {
description = application.description;
type = submodule application.module;
default = { };
}
) config.applications;
}; };
}; });
};
applications = mkOption {
description = "Collection of Fediversity applications";
type = attrsOf (submoduleWith {
modules = [
{
options = {
module = mkOption {
description = "The NixOS module for that application, for configuring that application";
type = deferredModule;
};
};
}
];
});
}; };
}; };
} }

View file

@ -1,26 +1,9 @@
{ inputs, sources, ... }:
{ {
_class = "flake"; _class = "flake";
perSystem = imports = [
{ pkgs, ... }: ./check/basic/flake-part.nix
{ ./check/cli/flake-part.nix
checks = { ./check/panel/flake-part.nix
deployment-basic = import ./check/basic { ];
inherit (pkgs.testers) runNixOSTest;
inherit inputs sources;
};
deployment-cli = import ./check/cli {
inherit (pkgs.testers) runNixOSTest;
inherit inputs sources;
};
deployment-panel = import ./check/panel {
inherit (pkgs.testers) runNixOSTest;
inherit inputs sources;
};
};
};
} }

View file

@ -1,37 +0,0 @@
/**
Modular function type
*/
{ config, lib, ... }:
let
inherit (lib) mkOption types;
inherit (types)
deferredModule
submodule
functionTo
optionType
;
in
{
options = {
input-type = mkOption {
type = deferredModule;
};
output-type = mkOption {
type = deferredModule;
};
function-type = mkOption {
type = optionType;
readOnly = true;
default = functionTo (submodule {
options = {
input = mkOption {
type = submodule config.input-type;
};
output = mkOption {
type = submodule config.output-type;
};
};
});
};
};
}

121
flake.lock generated
View file

@ -59,6 +59,22 @@
} }
}, },
"flake-compat_2": { "flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_3": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1733328505, "lastModified": 1733328505,
@ -74,7 +90,7 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat_3": { "flake-compat_4": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1696426674, "lastModified": 1696426674,
@ -127,6 +143,24 @@
} }
}, },
"flake-parts_3": { "flake-parts_3": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_3"
},
"locked": {
"lastModified": 1738453229,
"narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_4": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"nixops4-nixos", "nixops4-nixos",
@ -167,12 +201,32 @@
"type": "github" "type": "github"
} }
}, },
"git-hooks-nix": { "git-hooks": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"gitignore": "gitignore", "gitignore": "gitignore",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": {
"lastModified": 1742649964,
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"git-hooks-nix": {
"inputs": {
"flake-compat": "flake-compat_2",
"gitignore": "gitignore_2",
"nixpkgs": "nixpkgs_2"
},
"locked": { "locked": {
"lastModified": 1737465171, "lastModified": 1737465171,
"narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=", "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
@ -227,6 +281,27 @@
} }
}, },
"gitignore": { "gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gitignore_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nixops4-nixos", "nixops4-nixos",
@ -266,8 +341,8 @@
}, },
"nix": { "nix": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_2", "flake-compat": "flake-compat_3",
"flake-parts": "flake-parts_3", "flake-parts": "flake-parts_4",
"git-hooks-nix": "git-hooks-nix_2", "git-hooks-nix": "git-hooks-nix_2",
"nixfmt": "nixfmt", "nixfmt": "nixfmt",
"nixpkgs": [ "nixpkgs": [
@ -341,10 +416,10 @@
}, },
"nixops4": { "nixops4": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_2", "flake-parts": "flake-parts_3",
"nix": "nix", "nix": "nix",
"nix-cargo-integration": "nix-cargo-integration", "nix-cargo-integration": "nix-cargo-integration",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_3",
"nixpkgs-old": "nixpkgs-old" "nixpkgs-old": "nixpkgs-old"
}, },
"locked": { "locked": {
@ -363,7 +438,7 @@
}, },
"nixops4-nixos": { "nixops4-nixos": {
"inputs": { "inputs": {
"flake-parts": "flake-parts", "flake-parts": "flake-parts_2",
"git-hooks-nix": "git-hooks-nix", "git-hooks-nix": "git-hooks-nix",
"nixops4": "nixops4", "nixops4": "nixops4",
"nixops4-nixos": [ "nixops4-nixos": [
@ -445,6 +520,18 @@
"url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz" "url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz"
} }
}, },
"nixpkgs-lib_3": {
"locked": {
"lastModified": 1738452942,
"narHash": "sha256-vJzFZGaCpnmo7I6i416HaBLpC+hvcURh/BQwROcGIp8=",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz"
}
},
"nixpkgs-old": { "nixpkgs-old": {
"locked": { "locked": {
"lastModified": 1735563628, "lastModified": 1735563628,
@ -478,6 +565,22 @@
} }
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": {
"lastModified": 1730768919,
"narHash": "sha256-8AKquNnnSaJRXZxc5YmF/WfmxiHX6MMZZasRP6RRQkE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a04d33c0c3f1a59a2c1cb0c6e34cd24500e5a1dc",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1738410390, "lastModified": 1738410390,
"narHash": "sha256-xvTo0Aw0+veek7hvEVLzErmJyQkEcRk6PSR4zsRQFEc=", "narHash": "sha256-xvTo0Aw0+veek7hvEVLzErmJyQkEcRk6PSR4zsRQFEc=",
@ -518,7 +621,7 @@
}, },
"purescript-overlay": { "purescript-overlay": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_3", "flake-compat": "flake-compat_4",
"nixpkgs": [ "nixpkgs": [
"nixops4-nixos", "nixops4-nixos",
"nixops4", "nixops4",
@ -561,6 +664,8 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-parts": "flake-parts",
"git-hooks": "git-hooks",
"nixops4": [ "nixops4": [
"nixops4-nixos", "nixops4-nixos",
"nixops4" "nixops4"

115
flake.nix
View file

@ -1,52 +1,83 @@
{ {
inputs = { inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
git-hooks.url = "github:cachix/git-hooks.nix";
nixops4.follows = "nixops4-nixos/nixops4"; nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos"; nixops4-nixos.url = "github:nixops4/nixops4-nixos";
}; };
outputs = outputs =
inputs: inputs@{ self, flake-parts, ... }:
import ./mkFlake.nix inputs ( let
{ inputs, sources, ... }: sources = import ./npins;
inherit (import sources.flake-inputs) import-flake;
inherit (sources) git-hooks;
# XXX(@fricklerhandwerk): this atrocity is required to splice in a foreign Nixpkgs via flake-parts
# XXX - this is just importing a flake
nixpkgs = import-flake { src = sources.nixpkgs; };
# XXX - this overrides the inputs attached to `self`
inputs' = self.inputs // {
nixpkgs = nixpkgs;
};
self' = self // {
inputs = inputs';
};
in
# XXX - finally we override the overall set of `inputs` -- we need both:
# `flake-parts obtains `nixpkgs` from `self.inputs` and not from `inputs`.
flake-parts.lib.mkFlake
{ {
imports = [ inputs = inputs // {
"${sources.git-hooks}/flake-module.nix" inherit nixpkgs;
inputs.nixops4.modules.flake.default };
self = self';
./deployment/flake-part.nix specialArgs = {
./infra/flake-part.nix inherit sources;
./keys/flake-part.nix };
./secrets/flake-part.nix
./services/tests/flake-part.nix
];
perSystem =
{
pkgs,
lib,
system,
...
}:
{
checks = {
panel = (import ./. { inherit sources system; }).tests.panel.basic;
};
formatter = pkgs.nixfmt-rfc-style;
pre-commit.settings.hooks =
let
## Add a directory here if pre-commit hooks shouldn't apply to it.
optout = [ "npins" ];
excludes = map (dir: "^${dir}/") optout;
addExcludes = lib.mapAttrs (_: c: c // { inherit excludes; });
in
addExcludes {
nixfmt-rfc-style.enable = true;
deadnix.enable = true;
trim-trailing-whitespace.enable = true;
shellcheck.enable = true;
};
};
} }
); (
{ inputs, ... }:
{
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
imports = [
"${git-hooks}/flake-module.nix"
inputs.nixops4.modules.flake.default
./deployment/flake-part.nix
./infra/flake-part.nix
./keys/flake-part.nix
./secrets/flake-part.nix
];
perSystem =
{
pkgs,
lib,
...
}:
{
formatter = pkgs.nixfmt-rfc-style;
pre-commit.settings.hooks =
let
## Add a directory here if pre-commit hooks shouldn't apply to it.
optout = [ "npins" ];
excludes = map (dir: "^${dir}/") optout;
addExcludes = lib.mapAttrs (_: c: c // { inherit excludes; });
in
addExcludes {
nixfmt-rfc-style.enable = true;
deadnix.enable = true;
trim-trailing-whitespace.enable = true;
shellcheck.enable = true;
};
};
}
);
} }

View file

@ -1,13 +1,14 @@
# Infra # Infra
This directory contains the definition of [the VMs](../machines/machines.md) that host our This directory contains the definition of [the VMs](machines.md) that host our
infrastructure. infrastructure.
## Provisioning VMs with an initial configuration ## Provisioning VMs with an initial configuration
> NOTE[Niols]: This is still very manual and clunky. Two things will happen: NOTE[Niols]: This is very manual and clunky. Two things will happen. In the near
> 1. In the near future, I will improve the provisioning script to make this a bit less clunky. future, I will improve the provisioning script to make this a bit less clunky.
> 2. In the far future, NixOps4 will be able to communicate with Proxmox directly and everything will become much cleaner. In the far future, NixOps4 will be able to communicate with Proxmox directly and
everything will become much cleaner.
1. Choose names for your VMs. It is recommended to choose `fediXXX`, with `XXX` 1. Choose names for your VMs. It is recommended to choose `fediXXX`, with `XXX`
above 100. For instance, `fedi117`. above 100. For instance, `fedi117`.
@ -24,7 +25,8 @@ infrastructure.
Those files need to exist during provisioning, but their content matters only Those files need to exist during provisioning, but their content matters only
when updating the machines' configuration. when updating the machines' configuration.
> FIXME: Remove this step by making the provisioning script not fail with the public key does not exist yet. FIXME: Remove this step by making the provisioning script not fail with the
public key does not exist yet.
3. Run the provisioning script: 3. Run the provisioning script:
``` ```
@ -42,7 +44,7 @@ infrastructure.
ssh fedi117.abundos.eu 'sudo cat /etc/ssh/ssh_host_ed25519_key.pub' > keys/systems/fedi117.pub ssh fedi117.abundos.eu 'sudo cat /etc/ssh/ssh_host_ed25519_key.pub' > keys/systems/fedi117.pub
``` ```
> FIXME: Make the provisioning script do that for us. FIXME: Make the provisioning script do that for us.
7. Regenerate the list of machines: 7. Regenerate the list of machines:
``` ```
@ -54,7 +56,7 @@ infrastructure.
just enough for it to boot and be reachable. Go on to the next section to just enough for it to boot and be reachable. Go on to the next section to
update the machine and put an actual configuration. update the machine and put an actual configuration.
> FIXME: Figure out why the full configuration isn't on the machine at this FIXME: Figure out why the full configuration isn't on the machine at this
point and fix it. point and fix it.
## Updating existing VM configurations ## Updating existing VM configurations

View file

@ -1,13 +1,7 @@
{
config,
...
}:
{ {
_class = "nixos"; _class = "nixos";
users.users = { users.users = {
root.openssh.authorizedKeys.keys = config.users.users.procolix.openssh.authorizedKeys.keys;
procolix = { procolix = {
isNormalUser = true; isNormalUser = true;
extraGroups = [ "wheel" ]; extraGroups = [ "wheel" ];

View file

@ -1,10 +1,9 @@
{ sources, ... }: { modulesPath, ... }:
{ {
_class = "nixos"; _class = "nixos";
imports = [ imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
"${sources.nixpkgs}/nixos/modules/profiles/qemu-guest.nix"
];
boot = { boot = {
initrd = { initrd = {

View file

@ -48,9 +48,9 @@ in
## the secret's file. ## the secret's file.
age.secrets = concatMapAttrs ( age.secrets = concatMapAttrs (
name: secret: name: secret:
optionalAttrs (elem config.fediversityVm.hostPublicKey secret.publicKeys) { optionalAttrs (elem config.fediversityVm.hostPublicKey secret.publicKeys) ({
${removeSuffix ".age" name}.file = secrets.rootPath + "/${name}"; ${removeSuffix ".age" name}.file = secrets.rootPath + "/${name}";
} })
) secrets.mapping; ) secrets.mapping;
## FIXME: Remove direct root authentication once the NixOps4 NixOS provider ## FIXME: Remove direct root authentication once the NixOps4 NixOS provider
@ -58,8 +58,6 @@ in
users.users.root.openssh.authorizedKeys.keys = attrValues keys.contributors ++ [ users.users.root.openssh.authorizedKeys.keys = attrValues keys.contributors ++ [
# allow our panel vm access to the test machines # allow our panel vm access to the test machines
keys.panel keys.panel
# allow continuous deployment access
keys.cd
]; ];
}; };

View file

@ -27,19 +27,12 @@ let
_module.args = { _module.args = {
inherit inherit
inputs inputs
sources
keys keys
secrets secrets
; ;
}; };
nixos.module.imports = [
./common/proxmox-qemu-vm.nix
];
nixos.specialArgs = {
inherit sources;
};
imports = imports =
[ [
./common/resource.nix ./common/resource.nix
@ -47,6 +40,7 @@ let
++ ( ++ (
if isTestVm then if isTestVm then
[ [
./common/proxmox-qemu-vm.nix
../machines/operator/${vmName} ../machines/operator/${vmName}
{ {
nixos.module.users.users.root.openssh.authorizedKeys.keys = [ nixos.module.users.users.root.openssh.authorizedKeys.keys = [
@ -69,33 +63,17 @@ let
vmNames: vmNames:
{ providers, ... }: { providers, ... }:
{ {
# XXX: this type merge is for adding `specialArgs` to resource modules providers.local = inputs.nixops4.modules.nixops4Provider.local;
options.resources = mkOption { resources = genAttrs vmNames (vmName: {
type = type = providers.local.exec;
with lib.types; imports = [
lazyAttrsOf (submoduleWith { inputs.nixops4-nixos.modules.nixops4Resource.nixos
class = "nixops4Resource"; (makeResourceModule {
modules = [ ]; inherit vmName;
# TODO(@fricklerhandwerk): we may want to pass through all of `specialArgs` isTestVm = false;
# once we're sure it's sane. leaving it here for better control during refactoring. })
specialArgs = { ];
inherit sources; });
};
});
};
config = {
providers.local = inputs.nixops4.modules.nixops4Provider.local;
resources = genAttrs vmNames (vmName: {
type = providers.local.exec;
imports = [
inputs.nixops4-nixos.modules.nixops4Resource.nixos
(makeResourceModule {
inherit vmName;
isTestVm = false;
})
];
});
};
}; };
makeDeployment' = vmName: makeDeployment [ vmName ]; makeDeployment' = vmName: makeDeployment [ vmName ];

View file

@ -15,6 +15,7 @@ let
installer = installer =
{ {
config,
pkgs, pkgs,
lib, lib,
... ...

View file

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMlsYTtMx3hFO8B5B8iHaXL2JKj9izHeC+/AMhIWXBPs cd-age

View file

@ -35,5 +35,4 @@ in
contributors = collectKeys ./contributors; contributors = collectKeys ./contributors;
systems = collectKeys ./systems; systems = collectKeys ./systems;
panel = removeTrailingWhitespace (readFile ./panel-ssh-key.pub); panel = removeTrailingWhitespace (readFile ./panel-ssh-key.pub);
cd = removeTrailingWhitespace (readFile ./cd-ssh-key.pub);
} }

View file

@ -11,7 +11,7 @@ in
imports = [ imports = [
(import ../../../panel { }).module (import ../../../panel { }).module
"${sources.home-manager}/nixos" (import "${sources.home-manager}/nixos")
]; ];
security.acme = { security.acme = {

View file

@ -48,7 +48,7 @@ in
}; };
## NOTE: This is a physical machine, so is not covered by disko ## NOTE: This is a physical machine, so is not covered by disko
fileSystems."/" = lib.mkForce { fileSystems."/" = {
device = "rpool/root"; device = "rpool/root";
fsType = "zfs"; fsType = "zfs";
}; };
@ -58,7 +58,7 @@ in
fsType = "zfs"; fsType = "zfs";
}; };
fileSystems."/boot" = lib.mkForce { fileSystems."/boot" = {
device = "/dev/disk/by-uuid/50B2-DD3F"; device = "/dev/disk/by-uuid/50B2-DD3F";
fsType = "vfat"; fsType = "vfat";
options = [ options = [

View file

@ -1,4 +1,12 @@
{ pkgs, config, ... }: {
pkgs,
config,
# sources,
...
}:
let
sources = import ../../../npins;
in
{ {
_class = "nixos"; _class = "nixos";
@ -44,4 +52,53 @@
## For the Docker mode of the runner. ## For the Docker mode of the runner.
virtualisation.docker.enable = true; virtualisation.docker.enable = true;
virtualisation.oci-containers.containers."buildResult" =
let
name = "nix-runner";
tag = "latest";
base = import (sources.nix + "/docker.nix") {
inherit pkgs;
name = "nix-ci-base";
maxLayers = 10;
extraPkgs = with pkgs; [
nodejs_20 # nodejs is needed for running most 3rdparty actions
# add any other pre-installed packages here
];
# change this is you want
channelURL = "https://nixos.org/channels/nixpkgs-23.05";
nixConf = {
substituters = [
"https://cache.nixos.org/"
"https://nix-community.cachix.org"
# insert any other binary caches here
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
# insert the public keys for those binary caches here
];
# allow using the new flake commands in our workflows
experimental-features = [
"nix-command"
"flakes"
];
};
};
in
{
devices = [ "/dev/kvm:/dev/kvm" ];
image = "${name}:${tag}";
# https://icewind.nl/entry/gitea-actions-nix/
imageFile = pkgs.dockerTools.buildImage {
inherit name tag;
fromImage = base;
fromImageName = null;
fromImageTag = "latest";
copyToRoot = pkgs.buildEnv {
name = "image-root";
paths = [ pkgs.coreutils-full ];
pathsToLink = [ "/bin" ]; # add coreutils (which includes sleep) to /bin
};
};
};
} }

View file

@ -1,54 +0,0 @@
## This file contains a tweak of flake-parts's `mkFlake` function to splice in
## sources taken from npins.
## NOTE: Much of the logic in this file feels like it should be not super
## specific to fediversity. Could it make sense to extract the core of this to
## another place it feels closer to in spirit, such as @fricklerhandwerk's
## flake-inputs (which this code already depends on anyway, and which already
## contained two distinct helpers for migrating away from flakes)? cf
## https://git.fediversity.eu/Fediversity/Fediversity/pulls/447#issuecomment-8671
inputs@{ self, ... }:
let
sources = import ./npins;
inherit (import sources.flake-inputs) import-flake;
# XXX(@fricklerhandwerk): this atrocity is required to splice in a foreign Nixpkgs via flake-parts
# XXX - this is just importing a flake
nixpkgs = import-flake { src = sources.nixpkgs; };
# XXX - this overrides the inputs attached to `self`
inputs' = self.inputs // {
nixpkgs = nixpkgs;
};
self' = self // {
inputs = inputs';
};
flake-parts-lib = import "${sources.flake-parts}/lib.nix" { inherit (nixpkgs) lib; };
in
flakeModule:
flake-parts-lib.mkFlake
{
# XXX - finally we override the overall set of `inputs` -- we need both:
# `flake-parts obtains `nixpkgs` from `self.inputs` and not from `inputs`.
inputs = inputs // {
inherit nixpkgs;
};
self = self';
specialArgs = {
inherit sources;
};
}
{
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
imports = [ flakeModule ];
}

View file

@ -125,6 +125,22 @@
"url": "https://api.github.com/repos/bigskysoftware/htmx/tarball/v2.0.4", "url": "https://api.github.com/repos/bigskysoftware/htmx/tarball/v2.0.4",
"hash": "1c4zm3b7ym01ijydiss4amd14mv5fbgp1n71vqjk4alc35jlnqy2" "hash": "1c4zm3b7ym01ijydiss4amd14mv5fbgp1n71vqjk4alc35jlnqy2"
}, },
"nix": {
"type": "GitRelease",
"repository": {
"type": "GitHub",
"owner": "nixos",
"repo": "nix"
},
"pre_releases": false,
"version_upper_bound": null,
"release_prefix": null,
"submodules": false,
"version": "2.29.1",
"revision": "82debf3b591578eb2e7b151d2589626fad1679a2",
"url": "https://api.github.com/repos/nixos/nix/tarball/2.29.1",
"hash": "1xj5wawjw99qsyqfm3x02aydcg39rjksphnqg163plknifbzf8mc"
},
"nix-unit": { "nix-unit": {
"type": "Git", "type": "Git",
"repository": { "repository": {

View file

@ -45,7 +45,7 @@ in
''; '';
}; };
module = ./nix/configuration.nix; module = import ./nix/configuration.nix;
tests = pkgs.callPackage ./nix/tests.nix { }; tests = pkgs.callPackage ./nix/tests.nix { };
# re-export inputs so they can be overridden granularly # re-export inputs so they can be overridden granularly

View file

@ -202,8 +202,11 @@ in
}; };
}; };
# needed to place a config file with home-manager users.users.${name} = {
users.users.${name}.isNormalUser = true; # TODO[Niols]: change to system user or document why we specifically
# need a normal user.
isNormalUser = true;
};
users.groups.${name} = { }; users.groups.${name} = { };
systemd.services.${name} = { systemd.services.${name} = {

View file

@ -1,19 +1,17 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Jpc21A bBCQmvfRUwJuIXbpVJ092XUBVszGrb6gILGbgV9j9BY -> ssh-ed25519 Jpc21A 9edPaA2tT4SeYNTPzF0E157daC2o+JH/WQQCT+vLbFg
7DEGwhqdfqMs5cxXtlMkSTPjw4qhczBgW0dmoJ6dh6g C48EtLdhB75TTzfEZTw1DypicHiVlSmFzjfbqfO9N/8
-> ssh-ed25519 BAs8QA oiVedFC6UklEFCJUybGr93+XrddyCtV4r4TnE4nhpWI -> ssh-ed25519 BAs8QA T+kXpZg1v0XRkub5DWir7vYwO7KaOJLZBNYxxXiBUCw
xasnkP4NCl9TuYSE1u0Xi0b/PiwcrfHCz2QMnpTjLcU zBRwMTDpyI7twEwUGsmJYyYPw9btBx5Kakj1yT+XY8U
-> ssh-ed25519 ofQnlg LrMcWdaEUVyIgd/KznwJW/2sucIu5MuxDEcEJAmf8mA -> ssh-ed25519 ofQnlg 4UoEDY/tdKz8LrX1BkBU1/cn+vSaYLUl7xX9YmzANBY
p6pQoisuXre2J4r6ArV6C6lKO2J/aNdBFhqLPBoZ2wA 8CACq1n3AJgD9IyPN23iRvThqsfQFF5+jmkKnhun24U
-> ssh-ed25519 COspvA q2OGeVofPKyGCpr4Mf9VoaRvZCWTRl8n2mvkQOdTnyQ -> ssh-ed25519 COspvA HxcbkqHL+LpVmwb+Fo5JuUU+C+Pxzdxtb0yZHixwuzM
M+ffAGecJG/94k/Z5DdokltrZppS2IcxkZa8JKHwIMs 7FIhxdbjHJlgQQgjrHHUK5cecqs5aT7X3I8TWf8c2gc
-> ssh-ed25519 2XrTgw Bsz/G4QderToPSfMKOR6s5yWb0xCGUlsjGJxJYQNBRc -> ssh-ed25519 2XrTgw R6Ia8MVIZKPnNZ0rspZ34EqoY8fOLeB9H7vnvNBLg1g
JYrXZb8qj1Yi9u5bnI/WzuNxy7gyFLCTIUaGNmcOYnk 55NUqz5Yygt6FKJ3bR5iHxQp8G7S2gyFwrJNX1Pb/2Y
-> ssh-ed25519 awJeHA KKJMQSt0PvC6P+T/kxQv96tSBdLQLiY2f8q35IwGm28 -> ssh-ed25519 awJeHA hJdTuAScoewVMt7HWiisSkL0zSeClFzYzzKL84G893o
p7Cf2HLlPl0qmsO6Hh5zwVgKkEs3A6fdSBndMKsacbk ou780VLrW1s4d6L+lEVu3kXaGn4dvtFPA31supwEL50
-> ssh-ed25519 Fa25Dw 3m/qyannP4gjXxkUuO0LQRU8Z8HXOg4WReMDd7786y8 -> ssh-ed25519 Fa25Dw mJcqnXA3fQeoKrG7RJ7nVeLxPvrxqbj+lJdx6jQ9IR8
dNMyiBGeJDrBScE9TEyZZ7+MGMG6FLuoRTK82EVeX1w f5Q7mrQSSDsm1Z/uSAnvx66mgnRC3XaBLQrVL9f/Ijs
-> ssh-ed25519 i+ecmQ oCs4Ep2K75yjmUOh1ox4F25tGq+O/mZ2/c2E8+IRlEc --- W/KmboXTLV12X6WtVQKHNe+ZHvS2q9EHUZwofSgJSE8
0Wc9gDxhvHK5tEVM5kJ0mQXc3kp7tJ2JNHg54N0+tJ8 ^kûÚ h©0ÔkÇ ¢¸_Ç·ûQÞm7\òÖ}÷Áë?½qø<ÿm
--- mXrqbcHxjjkS5MrQaCVm4hTsAUEENAWlIYtiYx6rtas
ž`€úì}öÙ7Ù>­iŒbàéëÕè/& ɪŠwŽ„ì7àí[ã±Hˆc“

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -7,12 +7,11 @@ let
keys = import ../keys; keys = import ../keys;
contributors = attrValues keys.contributors; contributors = attrValues keys.contributors;
cd = [ keys.cd ];
in in
concatMapAttrs concatMapAttrs
(name: systems: { (name: systems: {
"${name}.age".publicKeys = contributors ++ systems ++ cd; "${name}.age".publicKeys = contributors ++ systems;
}) })
( (

View file

@ -1,19 +1,18 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Jpc21A NStZFZPTHMhVCnQ5Zkbl39vWztrxfsSXok24/e8H7QQ -> ssh-ed25519 Jpc21A EuMYAiZX+4A12eu19mIY7u+WYF7NJ9qJosQSVlxR6n8
JjHP6Cus76PGYYxpbnc2cSZ79zvdD8LISYDPbvXsnqU bK5CMXAmP23t1p9bgmqoVg4Qcu2qYKGc4t36v8e9eow
-> ssh-ed25519 BAs8QA iocHfHjWlEUsbtibqEbYDceAqURr2vjxuYapqon9hyU -> ssh-ed25519 BAs8QA IwRyitDNTzUPzQAUbDNEKjFiF8WPD/OyztOZQeoTEzw
ljL+olZdhWtHeV3uh3pOu22+sY13wPn2vKQDduPSqVs OwiTWvk4NmUgExav0uH6HlThDNU5hsKXfR6KHsFOV3I
-> ssh-ed25519 ofQnlg 9YVfMKyoP3+xtzg/ok2I9yf3YdIYoBpUJa/3d2N/8lI -> ssh-ed25519 ofQnlg 3TcMbLX1JsQL8+Gqy7IFZwykZr2BspvPCuZT1SHtnQQ
2yUalyj7O3c1YDA2xTb9QNYrFBDHwcyGBX3mydv0ifI Ci5OeBj2aiC8ut9jIEUMt3qfYH+cJrnVud6AH54Ndn8
-> ssh-ed25519 COspvA cOSNsZXBbhQ/B49fq3KwcY6siVrTz48doTrta/0d/Hw -> ssh-ed25519 COspvA 0t9f3Wu3ILv4QTJhwT619y+7XFrryCLbpIZC6aE+qQI
jcRtVxA/tVFM9btPAPI6zKk8BwAVlaQlvHC203MpmIQ oPQP48F6oO/tkqLZDdjkGtIap7KHiAknbpTNL6/yLaU
-> ssh-ed25519 2XrTgw d3EKtYkxjeJZ8kt3ofIklGmRwUCgTIB/WVVlvxggGRk -> ssh-ed25519 2XrTgw YOZsaYQH9vMH0QqSXGh8GyhRV4MbcBGPFfFaKpo3Ckk
IhcrpWN9xFsKRw9iCfYMONPOU7TpTt4kTBNwMDtk7zo kUShJbADA+6bpx2adxvzlI/0jSM5bIBfZfdSE/7Vm5Y
-> ssh-ed25519 awJeHA Ei64e3+FJDM6S8NP+YfEWEg9t72qTXZ0IdZE8dYQPm4 -> ssh-ed25519 awJeHA dF3m0hQWX9c0EezDr56Kt/F4d1Uim7NwvIX6zRws0Eo
ggRc86sXin06eXJkLbK8CdJFDa1237WMfSgwNd5ngmM pst243yrARODwrnyz8cJAzgDxdPOUsRbs7yPZePABFs
-> ssh-ed25519 dgBsjw 9etK6tNrFlWVAKTz5U0TitkiGYLKTad3QiRWVpLPrwM -> ssh-ed25519 dgBsjw PUYHcP/tgNnKyvlIoJRcNcW3zabVV1iHXIWfKqgW9xc
xHLzFnRtcvpVZYZrxWz5q4uadhHrHVlfqjteOWfIccE tXNjSuVH/g/oN5o75FPkFFpviF7SeFSN9kbqURvgMDE
-> ssh-ed25519 i+ecmQ SDTnYBLMOaH173B/wqaOifE6a90gSesRqMHmX7/iZFk --- wHgBAN9c6F6T5hFJGo8uH8zqDkQDwx3/jVNKUtQ3arE
kS9tuKnMXCXNUnoZ06DisOOyZHe/mZl4a0JRA+eynE8 «Ñ¢Á
--- C0R5WxDDCqQGxyvFoeNX838az0bjp55PGh//1NFG4LE ò@µú¡fÃ`m;ÕcæäU²€ùò£Íd…eSèyfv¿»¡€J?ø `œfj£Äa}lÃó ¿Úxç²BÇt2èfìôm08ÓoÝtRál9˜èx¤¢ŒÅžæ÷
ŠÉY—±³<EFBFBD>„ÏKRÇËej±éŒ7xÑí Óì¾7jÏ-œJý«[ÀF?Ÿ=-wXMC~)èŃ<E280BA>Éõb«ëƒCÜ4ÌÖÞOwý~¿š8ñv—ÙÜžèX»ØÆƒí!5¦

Binary file not shown.

Binary file not shown.

View file

@ -21,11 +21,11 @@ For those that know it, we could say that the current module is an analogous of
## Content of this directory ## Content of this directory
- [fediversity](./fediversity) contains the definition of the services. Look in - [fediversity][./fediversity] contains the definition of the services. Look in
particular at its `default.nix` that contains the definition of the options. particular at its `default.nix` that contains the definition of the options.
- [vm](./vm) contains options specific to making the service run in local QEMU - [vm][./vm] contains options specific to making the service run in local QEMU
VMs. These modules will for instance override the defaults to disable SSL, and VMs. These modules will for instance override the defaults to disable SSL, and
they will add virtualisation options to forward ports, for instance. they will add virtualisation options to forward ports, for instance.
- [tests](./tests) contain full NixOS tests of the services. - [tests][./tests] contain full NixOS tests of the services.

13
services/default.nix Normal file
View file

@ -0,0 +1,13 @@
{
system ? builtins.currentSystem,
sources ? import ../npins,
pkgs ? import sources.nixpkgs { inherit system; },
...
}:
{
tests = {
mastodon = pkgs.nixosTest ./tests/mastodon.nix;
pixelfed-garage = pkgs.nixosTest ./tests/pixelfed-garage.nix;
peertube = pkgs.nixosTest ./tests/peertube.nix;
};
}

View file

@ -49,7 +49,7 @@ in
displayName = mkOption { displayName = mkOption {
type = types.str; type = types.str;
description = "Name of the initial user, for humans"; description = "Name of the initial user, for humans";
default = config.fediversity.temp.initialUser.username; default = config.fediversity.temp.initialUser.name;
}; };
email = mkOption { email = mkOption {
type = types.str; type = types.str;
@ -65,16 +65,4 @@ in
}; };
}; };
}; };
config = {
## FIXME: This should clearly go somewhere else; and we should have a
## `staging` vs. `production` setting somewhere.
security.acme = {
acceptTerms = true;
# use a priority more urgent than mkDefault for panel deployment to work,
# yet looser than default so this will not clash with the setting in tests.
defaults.email = lib.modules.mkOverride 200 "something@fediversity.net";
# defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
};
};
} }

View file

@ -1,14 +0,0 @@
{ ... }:
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
checks = {
test-mastodon-service = pkgs.testers.runNixOSTest ./mastodon.nix;
test-pixelfed-garage-service = pkgs.testers.runNixOSTest ./pixelfed-garage.nix;
test-peertube-service = pkgs.testers.runNixOSTest ./peertube.nix;
};
};
}

View file

@ -6,7 +6,7 @@
{ pkgs, ... }: { pkgs, ... }:
let let
inherit (pkgs) lib writeText; lib = pkgs.lib;
## FIXME: this binding was not used, but maybe we want a side-effect or something? ## FIXME: this binding was not used, but maybe we want a side-effect or something?
# rebuildableTest = import ./rebuildableTest.nix pkgs; # rebuildableTest = import ./rebuildableTest.nix pkgs;
@ -69,17 +69,9 @@ in
expect expect
]; ];
environment.variables = { environment.variables = {
AWS_ACCESS_KEY_ID = "$(cat ${config.fediversity.mastodon.s3AccessKeyFile})"; AWS_ACCESS_KEY_ID = config.fediversity.garage.ensureKeys.mastodon.id;
AWS_SECRET_ACCESS_KEY = "$(cat ${config.fediversity.mastodon.s3SecretKeyFile})"; AWS_SECRET_ACCESS_KEY = config.fediversity.garage.ensureKeys.mastodon.secret;
}; };
services.mastodon.extraEnvFiles = [
# generate as: cd ${pkgs.mastodon}; IGNORE_ALREADY_SET_SECRETS=true RAILS_ENV=development ${pkgs.mastodon}/bin/rails db:encryption:init
(writeText "rest" ''
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=naGoEzeyjUmwIlmgZZmGQDWJrlWud5eX
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=A0tE1VJ7S3cjaOQ58mNkhrVFY7o5NKDB
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=tGHhd5Os7hLxa8QTzWwjyVLrvsj5VsCw
'')
];
}; };
}; };

View file

@ -113,7 +113,6 @@ let
${seleniumQuit}''; ${seleniumQuit}'';
dummyFile = pkgs.writeText "dummy" "dummy";
in in
{ {
name = "test-pixelfed-garage"; name = "test-pixelfed-garage";
@ -162,8 +161,8 @@ in
]; ];
environment.variables = { environment.variables = {
POST_MEDIA = ./fediversity.png; POST_MEDIA = ./fediversity.png;
AWS_ACCESS_KEY_ID = "$(cat ${config.fediversity.pixelfed.s3AccessKeyFile})"; AWS_ACCESS_KEY_ID = config.fediversity.garage.ensureKeys.pixelfed.id;
AWS_SECRET_ACCESS_KEY = "$(cat ${config.fediversity.pixelfed.s3SecretKeyFile})"; AWS_SECRET_ACCESS_KEY = config.fediversity.garage.ensureKeys.pixelfed.secret;
## without this we get frivolous errors in the logs ## without this we get frivolous errors in the logs
MC_REGION = "garage"; MC_REGION = "garage";
}; };
@ -171,12 +170,6 @@ in
users.users.selenium = { users.users.selenium = {
isNormalUser = true; isNormalUser = true;
}; };
fediversity.temp.initialUser = {
username = "dummy";
displayName = "dummy";
email = "dummy";
passwordFile = dummyFile;
};
}; };
}; };