diff --git a/README.md b/README.md index 4e13241..94fe8e1 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,12 @@ NixOS dotfiles and configuration for various hosts and users. - [`packages/`](./packages/): Custom packages. -- [`scripts/`](./lib/scripts): Utility scripts for managing the repository. - - [`add-host.sh`](./lib/scripts/add-host.sh): Instantiate the keys for a new host configuration. - - [`remove-host.sh`](./lib/scripts/remove-host.sh): Remove references to a host. - - [`update-keys.sh`](./lib/scripts/update-keys.sh): Update the encryption keys in all relevant files using `sops.yaml` configurations. - - [`update.sh`](./lib/scripts/update.sh): Update flake and all packages. +- [`scripts/`](./scripts): Utility scripts for managing the repository. + - [`add-host.sh`](./scripts/add-host.sh): Instantiate the keys for a new host configuration. + - [`remove-host.sh`](./scripts/remove-host.sh): Remove references to a host. + - [`update-keys.sh`](./scripts/update-keys.sh): Update the encryption keys in all relevant files using `sops.yaml` configurations. + - [`update.sh`](./scripts/update.sh): Update flake and all packages. + - [`cache.sh`](./scripts/cache.sh): Build all `nixosConfiguration`s and push them to `attic`. Any `options.nix` files create custom option definitions when present. diff --git a/flake.lock b/flake.lock index c51e8e4..6e9a266 100644 --- a/flake.lock +++ b/flake.lock @@ -511,11 +511,11 @@ "secrets": { "flake": false, "locked": { - "lastModified": 1756726520, - "narHash": "sha256-3HYpc5YQTrshyksigLMCsyZhvu7ghy38etfCUUtE4Hw=", + "lastModified": 1756900832, + "narHash": "sha256-sMne4dvYzcdbDVcMPY6NLVHiZbgjtDrxttKG0Vig8WQ=", "ref": "refs/heads/main", - "rev": "52906e7d78b7b4b74e8c1898924d7dc7fa3b4ab7", - "revCount": 36, + "rev": "adac63f6daffb4e14ce0fb94e93eb987e2460064", + "revCount": 38, "type": "git", "url": "ssh://git@karaolidis.com/karaolidis/nix-secrets.git" }, diff --git a/hosts/common/configs/system/nix/default.nix b/hosts/common/configs/system/nix/default.nix index eaab480..aee9cdf 100644 --- a/hosts/common/configs/system/nix/default.nix +++ b/hosts/common/configs/system/nix/default.nix @@ -1,25 +1,54 @@ -{ config, inputs, ... }: +{ + config, + inputs, + lib, + ... +}: { sops = { - secrets."git/credentials/github.com/tokens/public".sopsFile = - "${inputs.secrets}/domains/personal/secrets.yaml"; + secrets = { + "git/credentials/github.com/tokens/public".sopsFile = + "${inputs.secrets}/domains/personal/secrets.yaml"; - templates.nix-access-tokens = { - content = '' - access-tokens = github.com=${config.sops.placeholder."git/credentials/github.com/tokens/public"} - ''; - group = "users"; + "nix/cache/nix.karaolidis.com".sopsFile = "${inputs.secrets}/domains/personal/secrets.yaml"; + }; + + templates = { + nix-access-tokens = { + content = '' + access-tokens = github.com=${config.sops.placeholder."git/credentials/github.com/tokens/public"} + ''; + group = "users"; + mode = "0440"; + }; + + nix-netrc = { + content = '' + machine nix.karaolidis.com + password ${config.sops.placeholder."nix/cache/nix.karaolidis.com"} + ''; + group = "users"; + mode = "0440"; + }; }; }; nix = { settings = { + trusted-users = [ + "root" + "@wheel" + ]; use-xdg-base-directories = true; experimental-features = [ "nix-command" "flakes" ]; download-buffer-size = 524288000; + substituters = lib.mkBefore [ "https://nix.karaolidis.com/main" ]; + trusted-substituters = lib.mkBefore [ "https://nix.karaolidis.com/main" ]; + trusted-public-keys = lib.mkBefore [ "main:nJVRBnv73MDkwuV5sgm52m4E2ImOhWHvY12qzjPegAk=" ]; + netrc-file = config.sops.templates.nix-netrc.path; }; channel.enable = false; diff --git a/hosts/common/configs/user/console/attic/default.nix b/hosts/common/configs/user/console/attic/default.nix new file mode 100644 index 0000000..83f322e --- /dev/null +++ b/hosts/common/configs/user/console/attic/default.nix @@ -0,0 +1,33 @@ +{ user, home }: +{ + config, + inputs, + pkgs, + ... +}: +let + hmConfig = config.home-manager.users.${user}; +in +{ + home-manager.users.${user} = { + sops = { + secrets."nix/cache/nix.karaolidis.com".sopsFile = "${inputs.secrets}/domains/personal/secrets.yaml"; + + templates."attic" = { + content = builtins.readFile ( + (pkgs.formats.toml { }).generate "config.toml" { + default-server = "main"; + + servers."main" = { + endpoint = "https://nix.karaolidis.com/"; + token = hmConfig.sops.placeholder."nix/cache/nix.karaolidis.com"; + }; + } + ); + path = "${home}/.config/attic/config.toml"; + }; + }; + + home.packages = with pkgs; [ attic-client ]; + }; +} diff --git a/hosts/common/configs/user/console/home-manager/default.nix b/hosts/common/configs/user/console/home-manager/default.nix index 796ccbb..bcdba0a 100644 --- a/hosts/common/configs/user/console/home-manager/default.nix +++ b/hosts/common/configs/user/console/home-manager/default.nix @@ -1,5 +1,10 @@ { user, home }: -{ config, inputs, ... }: +{ + config, + inputs, + lib, + ... +}: { imports = [ inputs.home-manager.nixosModules.default ]; @@ -15,10 +20,18 @@ home.stateVersion = "24.11"; systemd.user.startServices = true; - nix.settings.experimental-features = [ - "nix-command" - "flakes" - ]; + nix.settings = { + use-xdg-base-directories = true; + experimental-features = [ + "nix-command" + "flakes" + ]; + download-buffer-size = 524288000; + substituters = lib.mkBefore [ "https://nix.karaolidis.com/main" ]; + trusted-substituters = lib.mkBefore [ "https://nix.karaolidis.com/main" ]; + trusted-public-keys = lib.mkBefore [ "main:nJVRBnv73MDkwuV5sgm52m4E2ImOhWHvY12qzjPegAk=" ]; + netrc-file = config.sops.templates.nix-netrc.path; + }; }; }; } diff --git a/hosts/common/configs/user/console/syncthing/default.nix b/hosts/common/configs/user/console/syncthing/default.nix index 89b504a..a594eb8 100644 --- a/hosts/common/configs/user/console/syncthing/default.nix +++ b/hosts/common/configs/user/console/syncthing/default.nix @@ -14,11 +14,13 @@ "syncthing/key" = { owner = user; group = "users"; + mode = "0440"; }; # openssl req -new -x509 -key key.pem -out cert.pem -days 9999 -subj "/CN=syncthing" "syncthing/cert" = { owner = user; group = "users"; + mode = "0440"; }; }; diff --git a/hosts/elara/default.nix b/hosts/elara/default.nix index 6c81cf5..5a94b62 100644 --- a/hosts/elara/default.nix +++ b/hosts/elara/default.nix @@ -43,7 +43,7 @@ networking.hostName = "elara"; - sas.build.private = true; + sas.build.private = false; environment.impermanence.enable = lib.mkForce false; } diff --git a/hosts/elara/users/nikara/default.nix b/hosts/elara/users/nikara/default.nix index a830732..6c43a58 100644 --- a/hosts/elara/users/nikara/default.nix +++ b/hosts/elara/users/nikara/default.nix @@ -14,6 +14,7 @@ in imports = [ (import ../../../common/configs/user { inherit user home; }) + (import ../../../common/configs/user/console/attic { inherit user home; }) (import ../../../common/configs/user/console/btop { inherit user home; }) (import ../../../common/configs/user/console/dive { inherit user home; }) (import ../../../common/configs/user/console/fastfetch { inherit user home; }) diff --git a/hosts/himalia/users/nick/default.nix b/hosts/himalia/users/nick/default.nix index 3bb432a..6487475 100644 --- a/hosts/himalia/users/nick/default.nix +++ b/hosts/himalia/users/nick/default.nix @@ -15,6 +15,7 @@ in (import ../../../common/configs/user { inherit user home; }) (import ../../../common/configs/user/console/android { inherit user home; }) + (import ../../../common/configs/user/console/attic { inherit user home; }) (import ../../../common/configs/user/console/brightnessctl { inherit user home; }) (import ../../../common/configs/user/console/btop { inherit user home; }) (import ../../../common/configs/user/console/dive { inherit user home; }) @@ -123,6 +124,7 @@ in ]; linger = true; uid = lib.strings.toInt (builtins.readFile ./uid); + openssh.authorizedKeys.keyFiles = [ "${inputs.secrets}/domains/personal/id_ed25519.pub" ]; }; services.getty.autologinUser = user; diff --git a/hosts/installer/default.nix b/hosts/installer/default.nix index 8fffa5e..5e0c466 100644 --- a/hosts/installer/default.nix +++ b/hosts/installer/default.nix @@ -33,6 +33,7 @@ ../common/configs/system/power ../common/configs/system/sops ../common/configs/system/ssh + ../common/configs/system/sshd ../common/configs/system/sudo ../common/configs/system/system ../common/configs/system/timezone diff --git a/hosts/installer/users/nick/default.nix b/hosts/installer/users/nick/default.nix index 35e3562..c4d3945 100644 --- a/hosts/installer/users/nick/default.nix +++ b/hosts/installer/users/nick/default.nix @@ -14,6 +14,7 @@ in imports = [ (import ../../../common/configs/user { inherit user home; }) + (import ../../../common/configs/user/console/attic { inherit user home; }) (import ../../../common/configs/user/console/brightnessctl { inherit user home; }) (import ../../../common/configs/user/console/btop { inherit user home; }) (import ../../../common/configs/user/console/fastfetch { inherit user home; }) @@ -63,6 +64,7 @@ in ]; linger = true; uid = lib.strings.toInt (builtins.readFile ./uid); + openssh.authorizedKeys.keyFiles = [ "${inputs.secrets}/domains/personal/id_ed25519.pub" ]; }; services.getty.autologinUser = user; diff --git a/hosts/jupiter/users/nick/default.nix b/hosts/jupiter/users/nick/default.nix index 2f9c71c..7c87355 100644 --- a/hosts/jupiter/users/nick/default.nix +++ b/hosts/jupiter/users/nick/default.nix @@ -14,6 +14,7 @@ in imports = [ (import ../../../common/configs/user { inherit user home; }) + (import ../../../common/configs/user/console/attic { inherit user home; }) (import ../../../common/configs/user/console/brightnessctl { inherit user home; }) (import ../../../common/configs/user/console/btop { inherit user home; }) (import ../../../common/configs/user/console/fastfetch { inherit user home; }) diff --git a/hosts/jupiter/users/storm/configs/console/podman/attic/default.nix b/hosts/jupiter/users/storm/configs/console/podman/attic/default.nix new file mode 100644 index 0000000..b3bcf1d --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/attic/default.nix @@ -0,0 +1,127 @@ +{ user, home }: +{ + config, + inputs, + pkgs, + ... +}: +let + hmConfig = config.home-manager.users.${user}; + inherit (hmConfig.virtualisation.quadlet) containers volumes networks; +in +{ + home-manager.users.${user} = { + sops = { + secrets = { + "attic/postgresql".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; + "attic/rs256".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; + "attic/admin".sopsFile = "${inputs.secrets}/hosts/jupiter/secrets.yaml"; + }; + + templates = { + attic-postgresql-env.content = '' + POSTGRES_PASSWORD=${hmConfig.sops.placeholder."attic/postgresql"} + ''; + + attic-env.content = '' + ATTIC_TOKEN=${hmConfig.sops.placeholder."attic/admin"} + ''; + + attic.content = builtins.readFile ( + (pkgs.formats.toml { }).generate "server.toml" { + listen = "[::]:8080"; + + allowed-hosts = [ "nix.karaolidis.com" ]; + api-endpoint = "https://nix.karaolidis.com/"; + + database.url = "postgres://attic:${ + hmConfig.sops.placeholder."attic/postgresql" + }@attic-postgresql:5432/attic"; + + storage = { + type = "local"; + path = "/var/lib/attic"; + }; + + chunking = { + nar-size-threshold = 65536; + min-size = 16384; + avg-size = 65536; + max-size = 262144; + }; + + compression = { + type = "zstd"; + level = 8; + }; + + garbage-collection = { + interval = "12 hours"; + default-retention-period = "1 month"; + }; + + jwt.signing.token-rs256-secret-base64 = hmConfig.sops.placeholder."attic/rs256"; + } + ); + }; + }; + + systemd.user.tmpfiles.rules = [ + "d /mnt/storage/private/storm/containers/storage/volumes/attic/_data 700 storm storm" + ]; + + virtualisation.quadlet = { + networks.attic = { }; + + volumes.attic-postgresql = { }; + + containers = { + attic = { + containerConfig = { + image = "docker-archive:${pkgs.dockerImages.attic}"; + networks = [ + networks.attic.ref + networks.traefik.ref + ]; + volumes = [ + "/mnt/storage/private/storm/containers/storage/volumes/attic/_data:/var/lib/attic" + "${hmConfig.sops.templates.attic.path}:/etc/attic/server.toml" + ]; + environmentFiles = [ hmConfig.sops.templates.attic-env.path ]; + exec = [ + "--config" + "/etc/attic/server.toml" + ]; + labels = [ + "traefik.enable=true" + "traefik.http.routers.attic.rule=Host(`nix.karaolidis.com`)" + ]; + }; + + unitConfig = { + After = [ + "${containers.attic-postgresql._serviceName}.service" + "sops-nix.service" + ]; + Requires = [ "${containers.attic-postgresql._serviceName}.service" ]; + }; + }; + + attic-postgresql = { + containerConfig = { + image = "docker-archive:${pkgs.dockerImages.postgresql}"; + networks = [ networks.attic.ref ]; + volumes = [ "${volumes.attic-postgresql.ref}:/var/lib/postgresql/data" ]; + environments = { + POSTGRES_DB = "attic"; + POSTGRES_USER = "attic"; + }; + environmentFiles = [ hmConfig.sops.templates.attic-postgresql-env.path ]; + }; + + unitConfig.After = [ "sops-nix.service" ]; + }; + }; + }; + }; +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/attic/post-start.sh b/hosts/jupiter/users/storm/configs/console/podman/attic/post-start.sh new file mode 100644 index 0000000..a43b248 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/attic/post-start.sh @@ -0,0 +1,22 @@ +# shellcheck shell=sh + +attic login main https://nix.karaolidis.com/ "$ATTIC_TOKEN" + +CACHE_NAME="main" + +while true; do + out=$(attic cache info "$CACHE_NAME" 2>&1) + status=$? + + if [ $status -eq 0 ]; then + break + elif echo "$out" | grep -q "NoSuchCache"; then + attic cache create "$CACHE_NAME" + elif echo "$out" | grep -q "404"; then + sleep 0.1 + else + echo "Unexpected error:" + echo "$out" + break + fi +done diff --git a/hosts/jupiter/users/storm/configs/console/podman/default.nix b/hosts/jupiter/users/storm/configs/console/podman/default.nix index f359b57..423eaf6 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/default.nix @@ -10,6 +10,7 @@ let in { imports = [ + (import ./attic { inherit user home; }) (import ./authelia { inherit user home; }) (import ./gitea { inherit user home; }) (import ./grafana { inherit user home; }) diff --git a/hosts/jupiter/users/storm/default.nix b/hosts/jupiter/users/storm/default.nix index c7089f4..f31b64c 100644 --- a/hosts/jupiter/users/storm/default.nix +++ b/hosts/jupiter/users/storm/default.nix @@ -14,6 +14,7 @@ in imports = [ (import ../../../common/configs/user { inherit user home; }) + (import ../../../common/configs/user/console/attic { inherit user home; }) (import ../../../common/configs/user/console/brightnessctl { inherit user home; }) (import ../../../common/configs/user/console/btop { inherit user home; }) (import ../../../common/configs/user/console/home-manager { inherit user home; }) diff --git a/overlays/attic-client/default.nix b/overlays/attic-client/default.nix new file mode 100644 index 0000000..941d163 --- /dev/null +++ b/overlays/attic-client/default.nix @@ -0,0 +1,5 @@ +final: prev: +# FIXME: https://github.com/zhaofengli/attic/pull/280 +prev.attic-client.overrideAttrs (oldAttrs: { + patches = oldAttrs.patches or [ ] ++ [ ./stdout-logging.patch ]; +}) diff --git a/overlays/attic-client/stdout-logging.patch b/overlays/attic-client/stdout-logging.patch new file mode 100644 index 0000000..4005c55 --- /dev/null +++ b/overlays/attic-client/stdout-logging.patch @@ -0,0 +1,321 @@ +diff --git a/client/src/command/cache.rs b/client/src/command/cache.rs +index af01378..0602b3b 100644 +--- a/client/src/command/cache.rs ++++ b/client/src/command/cache.rs +@@ -189,7 +189,7 @@ async fn create_cache(sub: Create) -> Result<()> { + }; + + api.create_cache(cache, request).await?; +- eprintln!( ++ println!( + "✨ Created cache \"{}\" on \"{}\"", + cache.as_str(), + server_name.as_str() +@@ -239,7 +239,7 @@ async fn configure_cache(sub: Configure) -> Result<()> { + let api = ApiClient::from_server_config(server.clone())?; + api.configure_cache(cache, &patch).await?; + +- eprintln!( ++ println!( + "✅ Configured \"{}\" on \"{}\"", + cache.as_str(), + server_name.as_str() +@@ -254,12 +254,12 @@ async fn destroy_cache(sub: Destroy) -> Result<()> { + let (server_name, server, cache) = config.resolve_cache(&sub.cache)?; + + if !sub.no_confirm { +- eprintln!("When you destory a cache:"); +- eprintln!(); +- eprintln!("1. Everyone will lose access."); +- eprintln!("2. The underlying data won't be deleted immediately."); +- eprintln!("3. You may not be able to create a cache of the same name."); +- eprintln!(); ++ println!("When you destory a cache:"); ++ println!(); ++ println!("1. Everyone will lose access."); ++ println!("2. The underlying data won't be deleted immediately."); ++ println!("3. You may not be able to create a cache of the same name."); ++ println!(); + + let answer: String = Input::new() + .with_prompt(format!( +@@ -278,7 +278,7 @@ async fn destroy_cache(sub: Destroy) -> Result<()> { + let api = ApiClient::from_server_config(server.clone())?; + api.destroy_cache(cache).await?; + +- eprintln!("🗑️ The cache was destroyed."); ++ println!("🗑️ The cache was destroyed."); + + Ok(()) + } +@@ -291,40 +291,40 @@ async fn show_cache_config(sub: Info) -> Result<()> { + let cache_config = api.get_cache_config(cache).await?; + + if let Some(is_public) = cache_config.is_public { +- eprintln!(" Public: {}", is_public); ++ println!(" Public: {}", is_public); + } + + if let Some(public_key) = cache_config.public_key { +- eprintln!(" Public Key: {}", public_key); ++ println!(" Public Key: {}", public_key); + } + + if let Some(substituter_endpoint) = cache_config.substituter_endpoint { +- eprintln!("Binary Cache Endpoint: {}", substituter_endpoint); ++ println!("Binary Cache Endpoint: {}", substituter_endpoint); + } + + if let Some(api_endpoint) = cache_config.api_endpoint { +- eprintln!(" API Endpoint: {}", api_endpoint); ++ println!(" API Endpoint: {}", api_endpoint); + } + + if let Some(store_dir) = cache_config.store_dir { +- eprintln!(" Store Directory: {}", store_dir); ++ println!(" Store Directory: {}", store_dir); + } + + if let Some(priority) = cache_config.priority { +- eprintln!(" Priority: {}", priority); ++ println!(" Priority: {}", priority); + } + + if let Some(upstream_cache_key_names) = cache_config.upstream_cache_key_names { +- eprintln!(" Upstream Cache Keys: {:?}", upstream_cache_key_names); ++ println!(" Upstream Cache Keys: {:?}", upstream_cache_key_names); + } + + if let Some(retention_period) = cache_config.retention_period { + match retention_period { + RetentionPeriodConfig::Period(period) => { +- eprintln!(" Retention Period: {:?}", period); ++ println!(" Retention Period: {:?}", period); + } + RetentionPeriodConfig::Global => { +- eprintln!(" Retention Period: Global Default"); ++ println!(" Retention Period: Global Default"); + } + } + } +diff --git a/client/src/command/login.rs b/client/src/command/login.rs +index 9abcea7..6cadd59 100644 +--- a/client/src/command/login.rs ++++ b/client/src/command/login.rs +@@ -28,7 +28,7 @@ pub async fn run(opts: Opts) -> Result<()> { + let mut config_m = config.as_mut(); + + if let Some(server) = config_m.servers.get_mut(&sub.name) { +- eprintln!("✍️ Overwriting server \"{}\"", sub.name.as_str()); ++ println!("✍️ Overwriting server \"{}\"", sub.name.as_str()); + + server.endpoint = sub.endpoint.to_owned(); + +@@ -38,7 +38,7 @@ pub async fn run(opts: Opts) -> Result<()> { + }); + } + } else { +- eprintln!("✍️ Configuring server \"{}\"", sub.name.as_str()); ++ println!("✍️ Configuring server \"{}\"", sub.name.as_str()); + + config_m.servers.insert( + sub.name.to_owned(), +diff --git a/client/src/command/push.rs b/client/src/command/push.rs +index b2bb661..5d39549 100644 +--- a/client/src/command/push.rs ++++ b/client/src/command/push.rs +@@ -91,7 +91,7 @@ impl PushContext { + + return Ok(()); + } else { +- eprintln!("⚙️ Pushing {num_missing_paths} paths to \"{cache}\" on \"{server}\" ({num_already_cached} already cached, {num_upstream} in upstream)...", ++ println!("⚙️ Pushing {num_missing_paths} paths to \"{cache}\" on \"{server}\" ({num_already_cached} already cached, {num_upstream} in upstream)...", + cache = self.cache_name.as_str(), + server = self.server_name.as_str(), + num_missing_paths = plan.store_path_map.len(), +diff --git a/client/src/command/use.rs b/client/src/command/use.rs +index 37d8cd6..d87f65e 100644 +--- a/client/src/command/use.rs ++++ b/client/src/command/use.rs +@@ -34,15 +34,15 @@ pub async fn run(opts: Opts) -> Result<()> { + let public_key = cache_config.public_key + .ok_or_else(|| anyhow!("The server did not tell us which public key it uses. Is signing managed by the client?"))?; + +- eprintln!( ++ println!( + "Configuring Nix to use \"{cache}\" on \"{server_name}\":", + cache = cache.as_str(), + server_name = server_name.as_str(), + ); + + // Modify nix.conf +- eprintln!("+ Substituter: {}", substituter); +- eprintln!("+ Trusted Public Key: {}", public_key); ++ println!("+ Substituter: {}", substituter); ++ println!("+ Trusted Public Key: {}", public_key); + + let mut nix_config = NixConfig::load().await?; + nix_config.add_substituter(&substituter); +@@ -50,7 +50,7 @@ pub async fn run(opts: Opts) -> Result<()> { + + // Modify netrc + if let Some(token) = server.token()? { +- eprintln!("+ Access Token"); ++ println!("+ Access Token"); + + let mut nix_netrc = NixNetrc::load().await?; + let host = Url::parse(&substituter)? +diff --git a/client/src/command/watch_store.rs b/client/src/command/watch_store.rs +index 24eaf7a..aec0c33 100644 +--- a/client/src/command/watch_store.rs ++++ b/client/src/command/watch_store.rs +@@ -91,7 +91,7 @@ pub async fn run(opts: Opts) -> Result<()> { + + watcher.watch(&store_dir, RecursiveMode::NonRecursive)?; + +- eprintln!( ++ println!( + "👀 Pushing new store paths to \"{cache}\" on \"{server}\"", + cache = cache.as_str(), + server = server_name.as_str(), +diff --git a/client/src/push.rs b/client/src/push.rs +index 309bd4b..2fea414 100644 +--- a/client/src/push.rs ++++ b/client/src/push.rs +@@ -595,7 +595,7 @@ pub async fn upload_path( + }; + + mp.suspend(|| { +- eprintln!( ++ println!( + "✅ {} ({})", + path.as_os_str().to_string_lossy(), + info_string +diff --git a/server/src/database/migration/m20230112_000004_migrate_nar_remote_files_to_chunks.rs b/server/src/database/migration/m20230112_000004_migrate_nar_remote_files_to_chunks.rs +index 42d70a6..6bbe585 100644 +--- a/server/src/database/migration/m20230112_000004_migrate_nar_remote_files_to_chunks.rs ++++ b/server/src/database/migration/m20230112_000004_migrate_nar_remote_files_to_chunks.rs +@@ -24,7 +24,7 @@ impl MigrationTrait for Migration { + // When this migration is run, we assume that there are no + // preexisting chunks. + +- eprintln!("* Migrating NARs to chunks..."); ++ println!("* Migrating NARs to chunks..."); + + // Add a temporary column into `chunk` to store the related `nar_id`. + manager +diff --git a/server/src/database/migration/m20230112_000005_drop_old_nar_columns.rs b/server/src/database/migration/m20230112_000005_drop_old_nar_columns.rs +index 9d29b66..7436b4a 100644 +--- a/server/src/database/migration/m20230112_000005_drop_old_nar_columns.rs ++++ b/server/src/database/migration/m20230112_000005_drop_old_nar_columns.rs +@@ -16,7 +16,7 @@ impl MigrationName for Migration { + #[async_trait::async_trait] + impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { +- eprintln!("* Migrating NAR schema..."); ++ println!("* Migrating NAR schema..."); + + if manager.get_database_backend() == DatabaseBackend::Sqlite { + // Just copy all data to a new table +diff --git a/server/src/lib.rs b/server/src/lib.rs +index 0314e69..89644e1 100644 +--- a/server/src/lib.rs ++++ b/server/src/lib.rs +@@ -217,7 +217,7 @@ async fn fallback(_: Uri) -> ServerResult<()> { + + /// Runs the API server. + pub async fn run_api_server(cli_listen: Option, config: Config) -> Result<()> { +- eprintln!("Starting API server..."); ++ println!("Starting API server..."); + + let state = StateInner::new(config).await; + +@@ -239,7 +239,7 @@ pub async fn run_api_server(cli_listen: Option, config: Config) -> R + .layer(TraceLayer::new_for_http()) + .layer(CatchPanicLayer::new()); + +- eprintln!("Listening on {:?}...", listen); ++ println!("Listening on {:?}...", listen); + + let listener = TcpListener::bind(&listen).await?; + +@@ -256,7 +256,7 @@ pub async fn run_api_server(cli_listen: Option, config: Config) -> R + + /// Runs database migrations. + pub async fn run_migrations(config: Config) -> Result<()> { +- eprintln!("Running migrations..."); ++ println!("Running migrations..."); + + let state = StateInner::new(config).await; + let db = state.database().await?; +diff --git a/server/src/main.rs b/server/src/main.rs +index c5f08df..3a37c23 100644 +--- a/server/src/main.rs ++++ b/server/src/main.rs +@@ -121,14 +121,14 @@ fn init_logging(tokio_console: bool) { + .init(); + + if tokio_console { +- eprintln!("Note: tokio-console is enabled"); ++ println!("Note: tokio-console is enabled"); + } + } + + fn dump_version() { + #[cfg(debug_assertions)] +- eprintln!("Attic Server {} (debug)", env!("CARGO_PKG_VERSION")); ++ println!("Attic Server {} (debug)", env!("CARGO_PKG_VERSION")); + + #[cfg(not(debug_assertions))] +- eprintln!("Attic Server {} (release)", env!("CARGO_PKG_VERSION")); ++ println!("Attic Server {} (release)", env!("CARGO_PKG_VERSION")); + } +diff --git a/server/src/oobe.rs b/server/src/oobe.rs +index d3d912d..98ef88c 100644 +--- a/server/src/oobe.rs ++++ b/server/src/oobe.rs +@@ -77,25 +77,25 @@ pub async fn run_oobe() -> Result<()> { + token.encode(&SignatureType::RS256(key), &None, &None)? + }; + +- eprintln!(); +- eprintln!("-----------------"); +- eprintln!("Welcome to Attic!"); +- eprintln!(); +- eprintln!("A simple setup using SQLite and local storage has been configured for you in:"); +- eprintln!(); +- eprintln!(" {}", config_path.to_str().unwrap()); +- eprintln!(); +- eprintln!("Run the following command to log into this server:"); +- eprintln!(); +- eprintln!(" attic login local http://localhost:8080 {root_token}"); +- eprintln!(); +- eprintln!("Documentations and guides:"); +- eprintln!(); +- eprintln!(" https://docs.attic.rs"); +- eprintln!(); +- eprintln!("Enjoy!"); +- eprintln!("-----------------"); +- eprintln!(); ++ println!(); ++ println!("-----------------"); ++ println!("Welcome to Attic!"); ++ println!(); ++ println!("A simple setup using SQLite and local storage has been configured for you in:"); ++ println!(); ++ println!(" {}", config_path.to_str().unwrap()); ++ println!(); ++ println!("Run the following command to log into this server:"); ++ println!(); ++ println!(" attic login local http://localhost:8080 {root_token}"); ++ println!(); ++ println!("Documentations and guides:"); ++ println!(); ++ println!(" https://docs.attic.rs"); ++ println!(); ++ println!("Enjoy!"); ++ println!("-----------------"); ++ println!(); + + Ok(()) + } diff --git a/overlays/default.nix b/overlays/default.nix index c70e9d5..dfb6c3e 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -1,6 +1,7 @@ final: prev: { android-tools = import ./android-tools final prev; + attic-client = import ./attic-client final prev; darktable = import ./darktable final prev; hyprland = import ./hyprland final prev; mpv = import ./mpv final prev; @@ -12,6 +13,7 @@ final: prev: // { dockerImages = prev.dockerImages or { } // { adguardhome = final.docker-image-adguardhome; + attic = final.docker-image-attic; authelia = final.docker-image-authelia; base = final.docker-image-base; comentario = final.docker-image-comentario; diff --git a/packages/default.nix b/packages/default.nix index 846cfaf..456798a 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -6,6 +6,7 @@ darktable-lua-scripts = import ./darktable/lua-scripts { inherit pkgs; }; docker-image-adguardhome = import ./docker/adguardhome { inherit pkgs; }; + docker-image-attic = import ./docker/attic { inherit pkgs; }; docker-image-authelia = import ./docker/authelia { inherit pkgs; }; docker-image-base = import ./docker/base { inherit pkgs; }; docker-image-comentario = import ./docker/comentario { inherit pkgs; }; diff --git a/packages/docker/attic/default.nix b/packages/docker/attic/default.nix new file mode 100644 index 0000000..5761dd4 --- /dev/null +++ b/packages/docker/attic/default.nix @@ -0,0 +1,34 @@ +{ pkgs, ... }: +let + entrypoint = pkgs.writeTextFile { + name = "entrypoint"; + executable = true; + destination = "/bin/entrypoint"; + text = builtins.readFile ./entrypoint.sh; + }; +in +pkgs.dockerTools.buildImage { + name = "attic"; + fromImage = pkgs.docker-image-base; + + copyToRoot = pkgs.buildEnv { + name = "root"; + paths = with pkgs; [ + entrypoint + attic-server + attic-client + ]; + pathsToLink = [ "/bin" ]; + }; + + config = { + Entrypoint = [ "entrypoint" ]; + ExposedPorts = { + "8080/tcp" = { }; + }; + WorkingDir = "/var/lib/atticd"; + Volumes = { + "/var/lib/atticd" = { }; + }; + }; +} diff --git a/packages/docker/attic/entrypoint.sh b/packages/docker/attic/entrypoint.sh new file mode 100644 index 0000000..ee8c603 --- /dev/null +++ b/packages/docker/attic/entrypoint.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +set -o errexit +set -o nounset + +atticd "$@" & +PID=$! + +if [ -f /etc/attic/post-start.sh ]; then + # shellcheck disable=SC1091 + . /etc/attic/post-start.sh +fi + +trap 'kill -KILL "$PID"' INT TERM +wait "$PID" +exit $? diff --git a/scripts/cache.sh b/scripts/cache.sh new file mode 100755 index 0000000..ed94ac2 --- /dev/null +++ b/scripts/cache.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +flake_json=$(nix flake show --json) + +build_and_push() { + local expr="$1" + nix build "$expr" --no-link --print-out-paths | while IFS= read -r path; do + attic push main "$path" + done +} + +jq -r '.nixosConfigurations | keys[]' <<<"$flake_json" | while IFS= read -r cfg; do + expr=".#nixosConfigurations.\"$cfg\".config.system.build.toplevel" + build_and_push "$expr" +done diff --git a/submodules/secrets b/submodules/secrets index 52906e7..adac63f 160000 --- a/submodules/secrets +++ b/submodules/secrets @@ -1 +1 @@ -Subproject commit 52906e7d78b7b4b74e8c1898924d7dc7fa3b4ab7 +Subproject commit adac63f6daffb4e14ce0fb94e93eb987e2460064