Harden zot registry, pt 1 #231
3 changed files with 85 additions and 34 deletions
Build ntfy nix container from forge mirror at v2.17.0
The nixpkgs ntfy-sh package is pinned at 2.15.0, creating a version skew with the Dockerfile (v2.17.0). Replace the pkgs.ntfy-sh reference with a custom derivation using fetchgit, buildNpmPackage, and buildGoModule targeting the forge mirror. Update container-version-check to extract versions from local nix files via regex before falling back to the Dagger nix-version function. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
commit
b98c6c1b3f
|
|
@ -1,20 +1,80 @@
|
|||
# Nix-built ntfy push notification server
|
||||
# Replaces the multi-stage Dockerfile (Node + Go + Alpine) with nixpkgs ntfy-sh
|
||||
# Builds v2.17.0 from forge mirror (nixpkgs has 2.15.0)
|
||||
# Built with dockerTools.buildLayeredImage for efficient layer caching
|
||||
{ pkgs ? import <nixpkgs> { } }:
|
||||
|
||||
let
|
||||
version = "2.17.0";
|
||||
|
||||
src = pkgs.fetchgit {
|
||||
url = "https://forge.ops.eblu.me/eblume/ntfy.git";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-/dxILAkye1HwYcybnx1WrMRK2jXZMrxal2ZKm6y2bWc=";
|
||||
};
|
||||
|
||||
ui = pkgs.buildNpmPackage {
|
||||
inherit src version;
|
||||
pname = "ntfy-sh-ui";
|
||||
npmDepsHash = "sha256-d73rymqCKalsjAwHSJshEovmUHJStfGt8wcZYN49sHY=";
|
||||
|
||||
prePatch = ''
|
||||
cd web/
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mv build/index.html build/app.html
|
||||
rm build/config.js
|
||||
mkdir -p $out
|
||||
mv build/ $out/site
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
|
||||
ntfy = pkgs.buildGoModule {
|
||||
inherit src version;
|
||||
pname = "ntfy-sh";
|
||||
vendorHash = "sha256-/mQ+UwBYz78mPVVwYgsSYatE00ce2AKXJdx+nl6oT8E=";
|
||||
|
||||
doCheck = false;
|
||||
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-X main.version=${version}"
|
||||
];
|
||||
|
||||
postPatch = ''
|
||||
sed -i 's# /bin/echo# echo#' Makefile
|
||||
'';
|
||||
|
||||
# Copy pre-built web UI; skip docs (create placeholder for go:embed)
|
||||
preBuild = ''
|
||||
cp -r ${ui}/site/ server/
|
||||
mkdir -p server/docs && touch server/docs/placeholder
|
||||
'';
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
description = "Send push notifications to your phone or desktop via PUT/POST";
|
||||
homepage = "https://ntfy.sh";
|
||||
license = licenses.asl20;
|
||||
mainProgram = "ntfy";
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
pkgs.dockerTools.buildLayeredImage {
|
||||
name = "blumeops/ntfy";
|
||||
tag = "latest";
|
||||
|
||||
contents = [
|
||||
pkgs.ntfy-sh
|
||||
ntfy
|
||||
pkgs.cacert
|
||||
pkgs.tzdata
|
||||
];
|
||||
|
||||
config = {
|
||||
Entrypoint = [ "${pkgs.ntfy-sh}/bin/ntfy" ];
|
||||
Entrypoint = [ "${ntfy}/bin/ntfy" ];
|
||||
Env = [
|
||||
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||
"TZDIR=${pkgs.tzdata}/share/zoneinfo"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
title: Fix ntfy Nix Version
|
||||
modified: 2026-02-20
|
||||
status: active
|
||||
tags:
|
||||
- how-to
|
||||
- containers
|
||||
|
|
@ -17,40 +16,24 @@ Override the nixpkgs ntfy-sh derivation to build v2.17.0 from the forge mirror,
|
|||
|
||||
Discovered during [[add-container-version-sync-check]]: the ntfy container has both a Dockerfile and a `default.nix`. The Dockerfile builds v2.17.0 from `forge.ops.eblu.me/eblume/ntfy.git`, but the nix derivation uses `pkgs.ntfy-sh` from nixpkgs which is pinned at 2.15.0. The version sync check currently excludes ntfy from nix version validation as a workaround.
|
||||
|
||||
## What to Do
|
||||
## What Was Done
|
||||
|
||||
Override the nixpkgs `ntfy-sh` derivation in `containers/ntfy/default.nix` to build from the forge mirror at the v2.17.0 tag. The nixpkgs derivation uses `buildGoModule` with a nested `buildNpmPackage` for the web UI.
|
||||
Replaced the nixpkgs `pkgs.ntfy-sh` reference in `containers/ntfy/default.nix` with a custom derivation that builds v2.17.0 from the forge mirror using `fetchgit`, `buildNpmPackage` (web UI), and `buildGoModule` (server). Docs are skipped (placeholder for `go:embed`, matching the Dockerfile approach).
|
||||
|
||||
### Hashes to Update
|
||||
|
||||
| Hash | What it covers | When to update |
|
||||
|------|---------------|----------------|
|
||||
| `src.hash` | Source tarball integrity | Always (new source) |
|
||||
| `vendorHash` | Go module dependencies | If `go.mod`/`go.sum` changed between 2.15.0 and 2.17.0 |
|
||||
| `npmDepsHash` | npm dependencies | If `web/package-lock.json` changed |
|
||||
|
||||
Use `lib.fakeHash` for each, attempt a build, and nix will report the expected hash.
|
||||
|
||||
### Steps
|
||||
|
||||
1. In `containers/ntfy/default.nix`, override `pkgs.ntfy-sh` with `fetchgit` pointing to `https://forge.ops.eblu.me/eblume/ntfy.git` at the v2.17.0 tag
|
||||
2. Update all three hashes via iterative builds
|
||||
3. Build and test with `dagger call build-nix --src=. --container-name=ntfy`
|
||||
4. Re-enable ntfy in `NIX_PACKAGE_MAP` in `mise-tasks/container-version-check`
|
||||
5. Verify `mise run container-version-check --all-files` passes
|
||||
The `container-version-check` script was updated to extract versions from local nix files via regex (`version = "X.Y.Z"`) before falling back to the Dagger `nix-version` function for unmodified nixpkgs packages. This avoids the issue where `nix eval nixpkgs#ntfy-sh.version` returns the upstream 2.15.0 instead of our overridden 2.17.0.
|
||||
|
||||
## Key Files
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `containers/ntfy/default.nix` | Override ntfy-sh derivation to build from forge |
|
||||
| `mise-tasks/container-version-check` | Re-add ntfy to `NIX_PACKAGE_MAP` |
|
||||
| `containers/ntfy/default.nix` | Custom derivation building v2.17.0 from forge |
|
||||
| `mise-tasks/container-version-check` | Regex-based local nix version extraction |
|
||||
|
||||
## Verification
|
||||
|
||||
- [ ] `dagger call build-nix --src=. --container-name=ntfy` produces a working image
|
||||
- [ ] `dagger call nix-version --package=ntfy-sh` returns 2.17.0 (or the overridden version is extractable)
|
||||
- [ ] `mise run container-version-check --all-files` passes with ntfy included
|
||||
- [x] `dagger call build-nix --src=. --container-name=ntfy` produces a working image
|
||||
- [x] Version extractable from local `default.nix` via regex (2.17.0)
|
||||
- [x] `mise run container-version-check --all-files` passes with ntfy included
|
||||
|
||||
## Related
|
||||
|
||||
|
|
|
|||
|
|
@ -45,14 +45,16 @@ CONTAINER_TO_SERVICE = {
|
|||
"kiwix-serve": "kiwix",
|
||||
}
|
||||
|
||||
# Container dir name → nixpkgs package name for dagger nix-version
|
||||
# ntfy excluded until nix derivation is updated to build v2.17.0 from forge
|
||||
# See: docs/how-to/zot/fix-ntfy-nix-version.md
|
||||
# Container dir name → nixpkgs package name for dagger nix-version.
|
||||
# Used for containers that use an unmodified nixpkgs package (version matches upstream).
|
||||
# Containers with local overrides (e.g. ntfy) declare version in default.nix
|
||||
# and are detected automatically via NIX_VERSION_PATTERN.
|
||||
NIX_PACKAGE_MAP = {
|
||||
"authentik": "authentik",
|
||||
}
|
||||
|
||||
VERSION_ARG_PATTERN = re.compile(r"^ARG\s+CONTAINER_APP_VERSION=(\S+)", re.MULTILINE)
|
||||
NIX_VERSION_PATTERN = re.compile(r'^\s*version\s*=\s*"([^"]+)"\s*;', re.MULTILINE)
|
||||
|
||||
app = typer.Typer()
|
||||
console = Console()
|
||||
|
|
@ -91,8 +93,14 @@ def changed_containers() -> set[str] | None:
|
|||
return names
|
||||
|
||||
|
||||
def get_nix_version(container_name: str) -> str | None:
|
||||
"""Extract nix package version via dagger. Returns None if unavailable."""
|
||||
def get_nix_version(container_name: str, nix_file: Path) -> str | None:
|
||||
"""Extract nix package version. Tries local nix file first, then dagger."""
|
||||
# Try extracting version declared directly in the nix file (local overrides)
|
||||
match = NIX_VERSION_PATTERN.search(nix_file.read_text())
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
# Fall back to dagger for unmodified nixpkgs packages
|
||||
pkg = NIX_PACKAGE_MAP.get(container_name)
|
||||
if pkg is None:
|
||||
return None
|
||||
|
|
@ -169,7 +177,7 @@ def main(
|
|||
|
||||
# Rule 2: nix derivation must produce a version
|
||||
if has_nix:
|
||||
nix_ver = get_nix_version(name)
|
||||
nix_ver = get_nix_version(name, nix_file)
|
||||
if nix_ver is not None:
|
||||
versions["nix"] = nix_ver
|
||||
elif name in NIX_PACKAGE_MAP:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue