Miniflux 2.2.19 + container.py migration + ty typechecker (#331)
All checks were successful
Build Container / detect (push) Successful in 3s
Build Container / build-dagger (miniflux) (push) Successful in 1m3s

## Summary

- Upgrade miniflux from 2.2.17 to 2.2.19 (security hardening, performance improvements)
- Migrate miniflux from Dockerfile to native Dagger container.py build
- Refactor `alpine_runtime()` helper to support existing users (nobody/65534)
- Add `ty` (Astral) Python typechecker to prek hooks

## Test plan

- [ ] `dagger call build --src=. --container-name=miniflux` succeeds
- [ ] `dagger call container-version --container-name=miniflux` returns 2.2.19
- [ ] `mise run container-version-check` passes
- [ ] `ty check` passes cleanly
- [ ] `prek run --all-files` passes
- [ ] CI builds container successfully
- [ ] Miniflux healthcheck passes after deploy from branch

Reviewed-on: #331
This commit is contained in:
Erich Blume 2026-04-12 08:54:32 -07:00
commit 138e23d525
12 changed files with 162 additions and 54 deletions

View file

@ -1,35 +0,0 @@
# Miniflux RSS feed reader
# Based on upstream packaging/docker/alpine/Dockerfile
ARG CONTAINER_APP_VERSION=2.2.17
ARG MINIFLUX_VERSION=${CONTAINER_APP_VERSION}
FROM golang:alpine3.22 AS build
ARG MINIFLUX_VERSION
RUN apk add --no-cache build-base git make
# Clone specific version
RUN git clone --depth 1 --branch ${MINIFLUX_VERSION} \
https://forge.ops.eblu.me/mirrors/miniflux.git /go/src/app
WORKDIR /go/src/app
RUN make miniflux
FROM alpine:3.22
ARG CONTAINER_APP_VERSION
LABEL org.opencontainers.image.title="Miniflux"
LABEL org.opencontainers.image.description="Miniflux is a minimalist and opinionated feed reader"
LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}"
LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops"
LABEL org.opencontainers.image.vendor="blumeops"
EXPOSE 8080
ENV LISTEN_ADDR=0.0.0.0:8080
RUN apk --no-cache add ca-certificates tzdata
COPY --from=build /go/src/app/miniflux /usr/bin/miniflux
USER 65534
CMD ["/usr/bin/miniflux"]

View file

@ -0,0 +1,61 @@
"""Miniflux RSS feed reader — native Dagger build.
Two-stage build: Go (backend with PIE), Alpine (runtime).
Source cloned from forge mirror.
"""
import dagger
from dagger import dag
from blumeops.containers import (
alpine_runtime,
clone_from_forge,
oci_labels,
)
VERSION = "2.2.19"
async def build(src: dagger.Directory) -> dagger.Container:
source = clone_from_forge("miniflux", VERSION)
# Stage 1: Build Go backend (PIE mode, matching upstream Makefile)
ldflags = f"-s -w -X 'miniflux.app/v2/internal/version.Version={VERSION}'"
backend = (
dag.container()
.from_("golang:alpine3.22")
.with_exec(["apk", "add", "--no-cache", "build-base", "git"])
.with_directory("/app", source)
.with_workdir("/app")
.with_env_variable("CGO_ENABLED", "1")
.with_exec(
[
"go",
"build",
"-buildmode=pie",
f"-ldflags={ldflags}",
"-o",
"/miniflux",
".",
]
)
)
# Stage 2: Runtime (uses Alpine's built-in nobody:65534)
runtime = alpine_runtime(
extra_apk=["ca-certificates", "tzdata"],
create_user=False,
)
runtime = oci_labels(
runtime,
title="Miniflux",
description="Miniflux is a minimalist and opinionated feed reader",
version=VERSION,
)
return (
runtime.with_file("/usr/bin/miniflux", backend.file("/miniflux"))
.with_exposed_port(8080)
.with_env_variable("LISTEN_ADDR", "0.0.0.0:8080")
.with_user("65534")
.with_default_args(args=["/usr/bin/miniflux"])
)