summaryrefslogtreecommitdiff
path: root/nix
diff options
context:
space:
mode:
authorseth <[email protected]>2023-12-15 02:40:21 -0500
committerseth <[email protected]>2023-12-15 16:41:13 -0500
commitaad424b4ba9989be4536390749ad0de351dd13ef (patch)
treefe99931dc498d69c8d09d23c4b5aed7661212231 /nix
parent03223e6e6d061a18b66a69092c59e6a0cb6d1d3f (diff)
flake: move nix to folder to nix/
Diffstat (limited to 'nix')
-rw-r--r--nix/deployment.nix86
-rw-r--r--nix/derivation.nix58
-rw-r--r--nix/dev.nix52
-rw-r--r--nix/module.nix144
-rw-r--r--nix/packages.nix28
-rw-r--r--nix/workflow.nix15
6 files changed, 383 insertions, 0 deletions
diff --git a/nix/deployment.nix b/nix/deployment.nix
new file mode 100644
index 0000000..9fb754e
--- /dev/null
+++ b/nix/deployment.nix
@@ -0,0 +1,86 @@
+{
+ inputs,
+ self,
+ ...
+}: {
+ flake.nixosModules.default = import ./module.nix self;
+
+ perSystem = {
+ lib,
+ pkgs,
+ system,
+ config,
+ inputs',
+ ...
+ }: let
+ name = "getchoo/teawiebot";
+
+ crossPkgsFor = lib.fix (finalAttrs: {
+ "x86_64-linux" = {
+ "x86_64" = pkgs.pkgsStatic;
+ "aarch64" = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic;
+ };
+
+ "aarch64-linux" = {
+ "x86_64" = pkgs.pkgsCross.musl64;
+ "aarch64" = pkgs.pkgsStatic;
+ };
+
+ "x86_64-darwin" = {
+ "x86_64" = pkgs.pkgsCross.musl64;
+ "aarch64" = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic;
+ };
+
+ "aarch64-darwin" = finalAttrs."x86_64-darwin";
+ });
+
+ wieFor = arch: let
+ target = "${arch}-unknown-linux-musl";
+ target' = builtins.replaceStrings ["-"] ["_"] target;
+ targetUpper = lib.toUpper target';
+
+ toolchain = with inputs'.fenix.packages;
+ combine [
+ minimal.cargo
+ minimal.rustc
+ targets.${target}.latest.rust-std
+ ];
+
+ naersk' = inputs.naersk.lib.${system}.override {
+ cargo = toolchain;
+ rustc = toolchain;
+ };
+
+ teawiebot = config.packages.teawiebot.override {
+ naersk = naersk';
+ optimizeSize = true;
+ };
+
+ inherit (crossPkgsFor.${system}.${arch}.stdenv) cc;
+ in
+ lib.getExe (
+ teawiebot.overrideAttrs (_:
+ lib.fix (finalAttrs: {
+ CARGO_BUILD_TARGET = target;
+ "CC_${target'}" = "${cc}/bin/${cc.targetPrefix}cc";
+ "CARGO_TARGET_${targetUpper}_RUSTFLAGS" = "-C target-feature=+crt-static";
+ "CARGO_TARGET_${targetUpper}_LINKER" = finalAttrs."CC_${target'}";
+ }))
+ );
+
+ containerFor = arch:
+ pkgs.dockerTools.buildLayeredImage {
+ inherit name;
+ tag = "latest-${arch}";
+ contents = [pkgs.dockerTools.caCertificates];
+ config.Cmd = [(wieFor arch)];
+
+ architecture = crossPkgsFor.${system}.${arch}.go.GOARCH;
+ };
+ in {
+ packages = {
+ container-x86_64 = containerFor "x86_64";
+ container-aarch64 = containerFor "aarch64";
+ };
+ };
+}
diff --git a/nix/derivation.nix b/nix/derivation.nix
new file mode 100644
index 0000000..061baea
--- /dev/null
+++ b/nix/derivation.nix
@@ -0,0 +1,58 @@
+{
+ lib,
+ stdenv,
+ naersk,
+ CoreFoundation,
+ Security,
+ SystemConfiguration,
+ self,
+ lto ? false,
+ optimizeSize ? false,
+}: let
+ filter = path: type: let
+ path' = toString path;
+ base = baseNameOf path';
+ parent = baseNameOf (dirOf path');
+
+ dirBlocklist = ["parts"];
+
+ matches = lib.any (suffix: lib.hasSuffix suffix base) [".rs"];
+ isCargo = base == "Cargo.lock" || base == "Cargo.toml";
+ isCopypasta = parent == "copypastas";
+ isAllowedDir = !(builtins.elem base dirBlocklist);
+ in
+ (type == "directory" && isAllowedDir) || matches || isCargo || isCopypasta;
+
+ filterSource = src:
+ lib.cleanSourceWith {
+ src = lib.cleanSource src;
+ inherit filter;
+ };
+in
+ naersk.buildPackage {
+ pname = "teawiebot";
+ version = builtins.substring 0 8 self.lastModifiedDate or "dirty";
+
+ src = filterSource ../.;
+
+ buildInputs = lib.optionals stdenv.hostPlatform.isDarwin [
+ CoreFoundation
+ Security
+ SystemConfiguration
+ ];
+
+ GIT_SHA = builtins.substring 0 7 self.rev or "dirty";
+
+ RUSTFLAGS =
+ lib.optionalString lto " -C lto=thin -C embed-bitcode=yes"
+ + lib.optionalString optimizeSize " -C codegen-units=1 -C strip=symbols -C opt-level=z";
+
+ meta = with lib; {
+ mainProgram = "teawiebot";
+ description = "funni bot";
+ homepage = "https://github.com/getchoo/teawiebot";
+ license = licenses.mit;
+ platforms = with platforms; linux ++ darwin;
+ maintainers = with maintainers; [getchoo];
+ };
+ }
diff --git a/nix/dev.nix b/nix/dev.nix
new file mode 100644
index 0000000..a796912
--- /dev/null
+++ b/nix/dev.nix
@@ -0,0 +1,52 @@
+{
+ perSystem = {
+ lib,
+ pkgs,
+ config,
+ ...
+ }: {
+ pre-commit.settings = {
+ hooks = {
+ actionlint.enable = true;
+ ${config.formatter.pname}.enable = true;
+ deadnix.enable = true;
+ nil.enable = true;
+ prettier.enable = true;
+ rustfmt.enable = true;
+ statix.enable = true;
+ };
+ };
+
+ proc.groups.daemons.processes = {
+ redis.command = lib.getExe' pkgs.redis "redis-server";
+ };
+
+ devShells = {
+ default = pkgs.mkShell {
+ packages = with pkgs; [
+ # general
+ actionlint
+ nodePackages_latest.prettier
+ config.proc.groups.daemons.package
+
+ # rust
+ cargo
+ rustc
+ clippy
+ rustfmt
+ rust-analyzer
+
+ # nix
+ config.formatter
+ deadnix
+ nil
+ statix
+ ];
+
+ RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
+ };
+ };
+
+ formatter = pkgs.alejandra;
+ };
+}
diff --git a/nix/module.nix b/nix/module.nix
new file mode 100644
index 0000000..d7709a4
--- /dev/null
+++ b/nix/module.nix
@@ -0,0 +1,144 @@
+self: {
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ cfg = config.services.teawiebot;
+ defaultUser = "teawiebot";
+
+ inherit
+ (lib)
+ getExe
+ literalExpression
+ mdDoc
+ mkEnableOption
+ mkIf
+ mkOption
+ mkPackageOption
+ optionals
+ types
+ ;
+in {
+ options.services.teawiebot = {
+ enable = mkEnableOption "teawiebot";
+ package = mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "teawiebot" {};
+
+ user = mkOption {
+ description = mdDoc ''
+ User under which the service should run. If this is the default value,
+ the user will be created, with the specified group as the primary
+ group.
+ '';
+ type = types.str;
+ default = defaultUser;
+ example = literalExpression ''
+ "bob"
+ '';
+ };
+
+ group = mkOption {
+ description = mdDoc ''
+ Group under which the service should run. If this is the default value,
+ the group will be created.
+ '';
+ type = types.str;
+ default = defaultUser;
+ example = literalExpression ''
+ "discordbots"
+ '';
+ };
+
+ redisUrl = mkOption {
+ description = mdDoc ''
+ Connection to a redis server. If this needs to include credentials
+ that shouldn't be world-readable in the Nix store, set environmentFile
+ and override the `REDIS_URL` entry.
+ Pass the string `local` to setup a local Redis database.
+ '';
+ type = types.str;
+ default = "local";
+ example = literalExpression ''
+ "redis://localhost/"
+ '';
+ };
+
+ environmentFile = mkOption {
+ description = mdDoc ''
+ Environment file as defined in {manpage}`systemd.exec(5)`
+ '';
+ type = types.nullOr types.path;
+ default = null;
+ example = literalExpression ''
+ "/run/agenix.d/1/teawieBot"
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.redis.servers.teawiebot = mkIf (cfg.redisUrl == "local") {
+ enable = true;
+ inherit (cfg) user;
+ port = 0; # disable tcp listener
+ };
+
+ systemd.services."teawiebot" = {
+ enable = true;
+ wantedBy = ["multi-user.target"];
+ after =
+ ["network.target"]
+ ++ optionals (cfg.redisUrl == "local") ["redis-teawiebot.service"];
+
+ script = ''
+ ${getExe cfg.package}
+ '';
+
+ environment = {
+ REDIS_URL =
+ if cfg.redisUrl == "local"
+ then "unix:${config.services.redis.servers.teawiebot.unixSocket}"
+ else cfg.redisUrl;
+ };
+
+ serviceConfig = {
+ Type = "simple";
+ Restart = "always";
+
+ EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
+
+ User = cfg.user;
+ Group = cfg.group;
+
+ # hardening
+ NoNewPrivileges = true;
+ PrivateDevices = true;
+ PrivateTmp = true;
+ PrivateUsers = true;
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectSystem = "strict";
+ RestrictNamespaces = "uts ipc pid user cgroup";
+ RestrictSUIDSGID = true;
+ Umask = "0007";
+ };
+ };
+
+ users = {
+ users = mkIf (cfg.user == defaultUser) {
+ ${defaultUser} = {
+ isSystemUser = true;
+ inherit (cfg) group;
+ };
+ };
+
+ groups = mkIf (cfg.group == defaultUser) {
+ ${defaultUser} = {};
+ };
+ };
+ };
+}
diff --git a/nix/packages.nix b/nix/packages.nix
new file mode 100644
index 0000000..4e1ab27
--- /dev/null
+++ b/nix/packages.nix
@@ -0,0 +1,28 @@
+{
+ self,
+ inputs,
+ ...
+}: {
+ perSystem = {
+ pkgs,
+ system,
+ config,
+ ...
+ }: {
+ packages = {
+ teawiebot = pkgs.callPackage ./derivation.nix {
+ inherit self;
+ inherit
+ (pkgs.darwin.apple_sdk.frameworks)
+ CoreFoundation
+ Security
+ SystemConfiguration
+ ;
+
+ naersk = inputs.naersk.lib.${system};
+ };
+
+ default = config.packages.teawiebot;
+ };
+ };
+}
diff --git a/nix/workflow.nix b/nix/workflow.nix
new file mode 100644
index 0000000..600a1bb
--- /dev/null
+++ b/nix/workflow.nix
@@ -0,0 +1,15 @@
+{
+ githubWorkflowGenerator = {
+ outputs = [
+ "checks"
+ "devShells"
+ "packages"
+ ];
+
+ overrides = {
+ checks.systems = ["x86_64-linux"];
+ devShells.systems = ["x86_64-linux"];
+ packages.systems = ["x86_64-linux"];
+ };
+ };
+}