{ config, lib, pkgs, ... }: with lib; let cacheUrl = "https://attic.cloonar.com"; cacheName = "cloonar-nixos"; publicKey = "cloonar-nixos:u0S8Q3CShMkXeBk/eo8iooqrcSBTwNGBxQDS9HfkseE="; authTokenFile = config.sops.secrets.attic_auth_token.path; # Post-build hook script that pushes to Attic atticPushHook = pkgs.writeShellScript "attic-push-hook" '' #!${pkgs.bash}/bin/bash set -euo pipefail # Load configuration from sops secrets at runtime ATTIC_CACHE="${cacheName}" ATTIC_URL="${cacheUrl}" # Check if we have the required configuration if [[ -z "$ATTIC_CACHE" ]] || [[ -z "$ATTIC_URL" ]]; then echo "Attic cache not configured, skipping push" >&2 exit 0 fi # Read the auth token from sops if available export ATTIC_AUTH_TOKEN ATTIC_AUTH_TOKEN=$(cat "${authTokenFile}") # Login to Attic cache echo "Logging in to Attic cache at $ATTIC_URL..." >&2 if ! ${pkgs.attic-client}/bin/attic login "$ATTIC_CACHE" "$ATTIC_URL" "$ATTIC_AUTH_TOKEN"; then echo "Failed to login to Attic cache, skipping push" >&2 exit 0 fi echo "Successfully logged in to Attic cache" >&2 # Function to check if a path exists in cache path_in_cache() { local path="$1" ${pkgs.attic-client}/bin/attic cache info "$ATTIC_CACHE" "$path" &>/dev/null } # Function to push a path to cache push_to_cache() { local path="$1" echo "Pushing $path to Attic cache..." >&2 if ${pkgs.attic-client}/bin/attic push "$ATTIC_CACHE" "$path"; then echo "Successfully pushed $path" >&2 else echo "Failed to push $path (non-fatal)" >&2 fi } # Read paths from OUT_PATHS environment variable (provided by Nix post-build-hook) echo "Reading paths from OUT_PATHS..." >&2 echo "DRV_PATH: $DRV_PATH" >&2 echo "OUT_PATHS: $OUT_PATHS" >&2 if [[ -z "$OUT_PATHS" ]]; then echo "No output paths provided, skipping push" >&2 exit 0 fi path_count=0 # Split OUT_PATHS by space and process each path for path in $OUT_PATHS; do path_count=$((path_count + 1)) echo "Processing path #$path_count: $path" >&2 if [[ -e "$path" ]]; then # Check if already in cache before pushing if ! path_in_cache "$path"; then push_to_cache "$path" else echo "Path $path already in cache, skipping" >&2 fi else echo "Path $path does not exist, skipping" >&2 fi done echo "Attic cache push completed (processed $path_count paths)" >&2 ''; in { sops.secrets.attic_auth_token = { sopsFile = ./secrets.yaml; }; # Create netrc file for authenticated cache access sops.secrets.attic_netrc = { sopsFile = ./secrets.yaml; mode = "0440"; group = "nixbld"; }; # Install attic client environment.systemPackages = with pkgs; [ attic-client ]; # Configure Nix settings nix.settings = { substituters = [ cacheUrl ]; trusted-public-keys = [ publicKey ]; post-build-hook = atticPushHook; netrc-file = config.sops.secrets.attic_netrc.path; }; # Create a systemd service for manual cache operations systemd.services.attic-push-closure = { description = "Push a closure to Attic cache"; serviceConfig = { Type = "oneshot"; ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.attic-client}/bin/attic push ${cacheName} $CLOSURE_PATH'"; EnvironmentFile = authTokenFile; }; }; }