Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions .github/workflows/nix-flake-vendor-hash.yml
Original file line number Diff line number Diff line change
@@ -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
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

171 changes: 171 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -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";
};
};
};
};
};
}