From 5f05313e6d94dd02865aa4f5c7c7d053feaf677a Mon Sep 17 00:00:00 2001 From: "Mikkel T. Hoegh" Date: Thu, 14 May 2026 18:12:44 +0200 Subject: [PATCH 1/2] Add flake.nix for installation on NixOS --- flake.lock | 61 +++++++++++++++++++ flake.nix | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..c6d2e2b --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1778672786, + "narHash": "sha256-Blg88K1jwG+P0Mr27+rKMFCufdrWkV3wWh9AdYtz0FQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "eef00dfd8a712b34af845f9350bac681b1228bd1", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..cc03525 --- /dev/null +++ b/flake.nix @@ -0,0 +1,171 @@ +{ + description = "Local Docker Development DNS"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + packages = { + ldddns = pkgs.buildGo126Module { + pname = "ldddns"; + version = self.shortRev or self.dirtyShortRev or "dev"; + + src = self; + + # Relax the go directive to match the Go version available in nixpkgs. + prePatch = '' + substituteInPlace go.mod --replace-fail "go 1.26.3" "go 1.26" + ''; + + vendorHash = "sha256-FI7kSIn1QNDcEqDECiGNVLZ5z7LWPxxunK6eKH3D46Y="; + + # Tests require /etc/protocols which is unavailable in the Nix sandbox. + doCheck = false; + + env.CGO_ENABLED = 0; + + ldflags = [ + "-s" + "-w" + "-X main.version=${self.shortRev or self.dirtyShortRev or "dev"}" + ]; + + buildFlags = [ "-trimpath" ]; + + postInstall = '' + mv $out/bin/ldddns.arnested.dk $out/bin/ldddns + ''; + + meta = { + description = "Local Docker Development DNS"; + homepage = "https://ldddns.arnested.dk"; + license = pkgs.lib.licenses.mit; + maintainers = [ ]; + platforms = pkgs.lib.platforms.linux; + }; + }; + + default = self.packages.${system}.ldddns; + }; + + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + go_1_26 + gopls + goreleaser + ]; + }; + } + ) + // { + nixosModules.default = + { + config, + lib, + pkgs, + ... + }: + let + cfg = config.services.ldddns; + in + { + options.services.ldddns = { + enable = lib.mkEnableOption "ldddns - Local Docker Development DNS"; + + package = lib.mkOption { + type = lib.types.package; + default = self.packages.${pkgs.stdenv.hostPlatform.system}.ldddns; + defaultText = lib.literalExpression "ldddns.packages.\${pkgs.stdenv.hostPlatform.system}.ldddns"; + description = "The ldddns package to use."; + }; + + hostnameLookup = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ + "env:VIRTUAL_HOST" + "containerName" + ]; + description = "Methods for looking up hostnames for containers."; + }; + + ignoreDockerComposeOneoff = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to ignore docker-compose oneoff containers."; + }; + + gops = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to enable the Google gops diagnostics agent."; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.ldddns = { + description = "Local Docker Development DNS"; + documentation = [ "https://ldddns.arnested.dk" ]; + bindsTo = [ + "docker.service" + "avahi-daemon.service" + ]; + after = [ + "docker.service" + "avahi-daemon.service" + ]; + wantedBy = [ "docker.service" ]; + + environment = { + LDDDNS_HOSTNAME_LOOKUP = lib.concatStringsSep "," cfg.hostnameLookup; + LDDDNS_IGNORE_DOCKER_COMPOSE_ONEOFF = + if cfg.ignoreDockerComposeOneoff then "true" else "false"; + LDDDNS_GOPS = if cfg.gops then "true" else "false"; + }; + + serviceConfig = { + Type = "notify"; + ExecStart = "${cfg.package}/bin/ldddns start"; + Restart = "on-failure"; + SupplementaryGroups = [ "docker" ]; + CapabilityBoundingSet = ""; + DevicePolicy = "closed"; + IPAddressDeny = "any"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateNetwork = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = [ "AF_UNIX" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallErrorNumber = "EPERM"; + SystemCallFilter = [ "@system-service" ]; + UMask = "0777"; + }; + }; + }; + }; + }; +} From 6aadf15fa2bc3f8873c77900c43d634b70154ead Mon Sep 17 00:00:00 2001 From: "Mikkel T. Hoegh" Date: Fri, 5 Jun 2026 11:01:07 +0200 Subject: [PATCH 2/2] Add action for automatic update of Nix flake vendorHash --- .github/workflows/nix-flake-vendor-hash.yml | 84 +++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 .github/workflows/nix-flake-vendor-hash.yml diff --git a/.github/workflows/nix-flake-vendor-hash.yml b/.github/workflows/nix-flake-vendor-hash.yml new file mode 100644 index 0000000..20b1234 --- /dev/null +++ b/.github/workflows/nix-flake-vendor-hash.yml @@ -0,0 +1,84 @@ +--- +name: Update vendorHash in Nix Flake +on: + push: + branches: + - main + paths: + - go.mod + - go.sum + pull_request_target: + paths: + - go.mod + - go.sum + +permissions: + contents: read + +jobs: + vendor-hash: + name: Update vendorHash + runs-on: ubuntu-24.04 + steps: + # Decide whether we trust this run *before* checking out any code. + # pull_request_target runs trusted base-repo workflow code with a + # writable token, so we must gate it: only Dependabot, or an actor with + # write access to the repo, may reach the checkout/build steps. Pushes + # to main are implicitly trusted (you cannot push there without access). + - name: Check authorization + id: auth + env: + GH_TOKEN: ${{ secrets.PAT_TOKEN }} + run: | + if [ "${{ github.event_name }}" = "push" ]; then + echo "authorized=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + actor='${{ github.actor }}' + if [ "$actor" = "dependabot[bot]" ]; then + echo "authorized=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + perm="$(gh api "repos/${{ github.repository }}/collaborators/$actor/permission" --jq '.permission' 2>/dev/null || echo none)" + case "$perm" in + admin | write | maintain) + echo "authorized=true" >> "$GITHUB_OUTPUT" + ;; + *) + echo "::notice::skipping vendorHash update for untrusted actor $actor ($perm)" + echo "authorized=false" >> "$GITHUB_OUTPUT" + ;; + esac + - uses: actions/checkout@v6 + if: steps.auth.outputs.authorized == 'true' + with: + # Push: the branch that was pushed (main). PR: the PR's head branch, + # so the fixup commit lands on the PR. Both are checked out by branch + # name (not detached) so we can commit and push back. + ref: >- + ${{ github.event_name == 'pull_request_target' + && github.event.pull_request.head.ref + || github.ref_name }} + token: ${{ secrets.PAT_TOKEN }} + - uses: DeterminateSystems/nix-installer-action@main + if: steps.auth.outputs.authorized == 'true' + - name: Recompute vendorHash + if: steps.auth.outputs.authorized == 'true' + run: | + # Force a mismatch so Nix prints the correct hash, then write it back. + sed -i 's|vendorHash = "[^"]*"|vendorHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="|' flake.nix + hash="$(nix build .#ldddns 2>&1 | sed -n 's/.*got:[[:space:]]*//p')" + if [ -z "$hash" ]; then + echo "::error::could not determine vendorHash from nix build output" >&2 + exit 1 + fi + sed -i "s|vendorHash = \"sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"|vendorHash = \"$hash\"|" flake.nix + - name: Commit if changed + if: steps.auth.outputs.authorized == 'true' + run: | + if ! git diff --quiet -- flake.nix; then + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + git commit -am 'Update Nix Flake vendorHash for Go module changes' + git push + fi