From 77ef642e96bddd566ae978bfb7dc4ab7f161c952 Mon Sep 17 00:00:00 2001
From: Sheogorath <sheogorath@shivering-isles.com>
Date: Sun, 3 Sep 2023 23:18:09 +0200
Subject: [PATCH] ci(earthly): Provide current version

---
 Earthfile                           |  42 +++++++++++
 images/.utils/.make-release-support | 105 --------------------------
 images/.utils/.skip-earthly         |   0
 images/.utils/Earthfile             |   8 ++
 images/.utils/container-build.mk    | 112 ----------------------------
 images/.utils/gitlab-ci.yaml        |  74 ++++++++----------
 images/demo/Dockerfile              |   3 -
 images/demo/Earthfile               |   6 ++
 images/demo/Makefile                |   8 --
 images/dovecot/.release             |   2 +-
 images/dovecot/Dockerfile           |  47 ------------
 images/dovecot/Earthfile            |  58 ++++++++++++++
 images/dovecot/Makefile             |   2 -
 images/koolbox/.release             |   2 +-
 images/koolbox/Earthfile            |  13 ++++
 images/mirror/.skip-earthly         |   0
 images/mirror/Earthfile             |  25 +++++++
 images/postfix/.release             |   2 +-
 images/postfix/Dockerfile           |  31 --------
 images/postfix/Earthfile            |  44 +++++++++++
 images/postfix/Makefile             |   2 -
 images/query-exposer/.release       |   2 +-
 images/query-exposer/Dockerfile     |  16 ----
 images/query-exposer/Earthfile      |  38 ++++++++++
 images/query-exposer/Makefile       |   2 -
 images/synadm/.release              |   2 +-
 images/synadm/Earthfile             |  13 ++++
 renovate.json                       |   8 ++
 28 files changed, 291 insertions(+), 376 deletions(-)
 create mode 100644 Earthfile
 delete mode 100644 images/.utils/.make-release-support
 create mode 100644 images/.utils/.skip-earthly
 create mode 100644 images/.utils/Earthfile
 delete mode 100644 images/.utils/container-build.mk
 delete mode 100644 images/demo/Dockerfile
 create mode 100644 images/demo/Earthfile
 delete mode 100644 images/demo/Makefile
 delete mode 100644 images/dovecot/Dockerfile
 create mode 100644 images/dovecot/Earthfile
 delete mode 100644 images/dovecot/Makefile
 create mode 100644 images/koolbox/Earthfile
 create mode 100644 images/mirror/.skip-earthly
 create mode 100644 images/mirror/Earthfile
 delete mode 100644 images/postfix/Dockerfile
 create mode 100644 images/postfix/Earthfile
 delete mode 100644 images/postfix/Makefile
 delete mode 100644 images/query-exposer/Dockerfile
 create mode 100644 images/query-exposer/Earthfile
 delete mode 100644 images/query-exposer/Makefile
 create mode 100644 images/synadm/Earthfile

diff --git a/Earthfile b/Earthfile
new file mode 100644
index 000000000..c60ab1d21
--- /dev/null
+++ b/Earthfile
@@ -0,0 +1,42 @@
+VERSION 0.7
+
+ARG --global CONTAINER_REGISTRY=quay.io/shivering-isles
+
+# Build all container images
+images:
+    BUILD +images-earthly
+    BUILD +images-dockerfile
+
+images-src:
+    FROM quay.io/fedora/fedora:38
+    COPY images/ ./images
+
+images-earthly:
+    FROM +images-src
+    FOR dir IN $(find ./images -type d -execdir test -f {}/Earthfile -a \! -e {}/.skip-earthly \; -print)
+        BUILD "${dir}+container" --registry="$CONTAINER_REGISTRY/$(basename ${dir})"
+    END
+
+images-dockerfile:
+    FROM +images-src
+    FOR dir IN $(find ./images -type d -execdir test -f {}/Dockerfile -a \! -e {}/Earthfile -a \! -e {}/.skip-earthly \; -print)
+        FROM DOCKERFILE -f "${dir}/Dockerfile" "${dir}"
+        SAVE IMAGE "$CONTAINER_REGISTRY/$(basename ${dir})"
+    END
+
+changelog:
+  FROM quay.io/git-chglog/git-chglog:0.15.4
+  COPY . /src
+  WORKDIR /src
+  RUN git-chglog --template .chglog/unreleased.tpl.md --next-tag "v$(date +%y.%m)" --output RELEASENOTES.md
+  SAVE ARTIFACT RELEASENOTES.md AS LOCAL RELEASENOTES.md
+
+# Allows to merge branches in the origin remote, this helps to keep everything signed
+merge:
+    LOCALLY
+    ARG --required branch
+    RUN git fetch
+    RUN git merge --no-ff origin/${branch} --no-edit
+    RUN git push
+    RUN git push origin --delete ${branch}
+
diff --git a/images/.utils/.make-release-support b/images/.utils/.make-release-support
deleted file mode 100644
index 31b56a1db..000000000
--- a/images/.utils/.make-release-support
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/bin/bash
-#
-#   Copyright 2015  Xebia Nederland B.V.
-#
-#   Licensed under the Apache License, Version 2.0 (the "License");
-#   you may not use this file except in compliance with the License.
-#   You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-#   Unless required by applicable law or agreed to in writing, software
-#   distributed under the License is distributed on an "AS IS" BASIS,
-#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#   See the License for the specific language governing permissions and
-#   limitations under the License.
-#
-function hasChanges() {
-	test -n "$(git status -s .)"
-}
-
-function getRelease() {
-	awk -F= '/^release=/{print $2}' .release
-}
-
-function getBaseTag() {
-		sed -n -e "s/^tag=\(.*\)$(getRelease)\$/\1/p" .release
-}
-
-function getTag() {
-	if [ -z "$1" ] ; then
-		awk -F= '/^tag/{print $2}' .release
-	else
-		echo "$(getBaseTag)$1"
-	fi
-}
-
-function setRelease() {
-	if [ -n "$1" ] ; then
-		sed -i.x -e "s~^tag=.*~tag=$(getTag $1)~" .release
-		sed -i.x -e "s~^release=.*~release=$1~g" .release
-		rm -f .release.x
-		runPreTagCommand "$1"
-	else
-		echo "ERROR: missing release version parameter " >&2
-		return 1
-	fi
-}
-
-function runPreTagCommand() {
-	if [ -n "$1" ] ; then
-		COMMAND=$(sed -n -e "s/@@RELEASE@@/$1/g" -e 's/^pre_tag_command=\(.*\)/\1/p' .release)
-		if [ -n "$COMMAND" ] ; then
-			if ! OUTPUT=$(bash -c "$COMMAND" 2>&1) ; then echo $OUTPUT >&2 && exit 1 ; fi
-		fi
-	else
-		echo "ERROR: missing release version parameter " >&2
-		return 1
-	fi
-}
-
-function tagExists() {
-	tag=${1:-$(getTag)}
-	test -n "$tag" && test -n "$(git tag | grep "^$tag\$")"
-}
-
-function differsFromRelease() {
-	tag=$(getTag)
-	! tagExists $tag || test -n "$(git diff --shortstat -r $tag .)"
-}
-
-function getVersion() {
-	result=$(getRelease)
-
-	if differsFromRelease; then
-		result="$result-$(git log -n 1 --format=%h .)"
-	fi
-
-	if hasChanges ; then
-		result="$result-dirty"
-	fi
-	echo $result
-}
-
-function nextPatchLevel() {
-	version=${1:-$(getRelease)}
-	major_and_minor=$(echo $version | cut -d. -f1,2)
-	patch=$(echo $version | cut -d. -f3)
-	version=$(printf "%s.%d" $major_and_minor $(($patch + 1)))
-	echo $version
-}
-
-function nextMinorLevel() {
-	version=${1:-$(getRelease)}
-	major=$(echo $version | cut -d. -f1);
-	minor=$(echo $version | cut -d. -f2);
-	version=$(printf "%d.%d.0" $major $(($minor + 1))) ;
-	echo $version
-}
-
-function nextMajorLevel() {
-	version=${1:-$(getRelease)}
-	major=$(echo $version | cut -d. -f1);
-	version=$(printf "%d.0.0" $(($major + 1)))
-	echo $version
-}
diff --git a/images/.utils/.skip-earthly b/images/.utils/.skip-earthly
new file mode 100644
index 000000000..e69de29bb
diff --git a/images/.utils/Earthfile b/images/.utils/Earthfile
new file mode 100644
index 000000000..d8de15e28
--- /dev/null
+++ b/images/.utils/Earthfile
@@ -0,0 +1,8 @@
+VERSION 0.7
+
+SCAN:
+    COMMAND
+    FROM ../mirror+trivy
+    WITH DOCKER --load image=+container
+        RUN trivy image image:latest
+    END
\ No newline at end of file
diff --git a/images/.utils/container-build.mk b/images/.utils/container-build.mk
deleted file mode 100644
index 316321b83..000000000
--- a/images/.utils/container-build.mk
+++ /dev/null
@@ -1,112 +0,0 @@
-#
-#   Copyright 2015  Xebia Nederland B.V.
-#   Copyright 2022  Christoph (Sheogorath) Kern
-#
-#   Licensed under the Apache License, Version 2.0 (the "License");
-#   you may not use this file except in compliance with the License.
-#   You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-#   Unless required by applicable law or agreed to in writing, software
-#   distributed under the License is distributed on an "AS IS" BASIS,
-#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#   See the License for the specific language governing permissions and
-#   limitations under the License.
-#
-REGISTRY_HOST=docker.io
-USERNAME=$(shell podman login --get-login $(REGISTRY_HOST))
-NAME=$(shell basename $(CURDIR))
-
-RELEASE_SUPPORT := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))/.make-release-support
-IMAGE=$(REGISTRY_HOST)/$(USERNAME)/$(NAME)
-
-VERSION=$(shell . $(RELEASE_SUPPORT) ; getVersion)
-TAG=$(shell . $(RELEASE_SUPPORT); getTag)
-
-SHELL=/bin/bash
-
-DOCKER_BUILD_CONTEXT=.
-DOCKER_FILE_PATH=Dockerfile
-
-.PHONY: preflight pre-build docker-build post-build build release patch-release minor-release major-release tag check-status check-release showver \
-	push pre-push do-push post-push
-
-preflight:
-	# Check for required tools
-	command -v podman > /dev/null
-
-build: pre-build docker-build post-build ## build and tag container
-
-pre-build: preflight
-
-
-post-build:
-
-
-pre-push:
-
-
-post-push:
-
-
-
-docker-build: .release
-	podman build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(VERSION) $(DOCKER_BUILD_CONTEXT) -f $(DOCKER_FILE_PATH)
-	podman tag $(IMAGE):$(VERSION) $(IMAGE):latest
-
-.release:
-	@echo "release=0.0.0" > .release
-	@echo "tag=$(NAME)-0.0.0" >> .release
-	@echo INFO: .release created
-	@cat .release
-
-
-release: check-status check-release build push ## build release from current git tag and push to registry
-
-
-push: pre-push do-push post-push ## Push current image to registry
-
-do-push:
-	podman push $(IMAGE):$(VERSION)
-	podman push $(IMAGE):latest
-
-snapshot: build push ## Build current state and push to registry
-
-showver: .release ## Print current container tag
-	@. $(RELEASE_SUPPORT); getVersion
-
-tag-patch-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextPatchLevel)
-tag-patch-release: .release tag
-
-tag-minor-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMinorLevel)
-tag-minor-release: .release tag
-
-tag-major-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMajorLevel)
-tag-major-release: .release tag
-
-patch-release: tag-patch-release release ## Release new patch version
-	@echo $(VERSION)
-
-minor-release: tag-minor-release release ## Release new minor version
-	@echo $(VERSION)
-
-major-release: tag-major-release release ## Release new major version
-	@echo $(VERSION)
-
-
-tag: TAG=$(shell . $(RELEASE_SUPPORT); getTag $(VERSION))
-tag: check-status
-	@. $(RELEASE_SUPPORT) ; ! tagExists $(TAG) || (echo "ERROR: tag $(TAG) for version $(VERSION) already tagged in git" >&2 && exit 1) ;
-	@. $(RELEASE_SUPPORT) ; setRelease $(VERSION)
-	git add .
-	git commit -m "bumped to version $(VERSION)" ;
-	git tag $(TAG) ;
-	@ if [ -n "$(shell git remote -v)" ] ; then git push --tags ; else echo 'no remote to push tags to' ; fi
-
-check-status:
-	@. $(RELEASE_SUPPORT) ; ! hasChanges || (echo "ERROR: there are still outstanding changes" >&2 && exit 1) ;
-
-check-release: .release
-	@. $(RELEASE_SUPPORT) ; tagExists $(TAG) || (echo "ERROR: version not yet tagged in git. make [minor,major,patch]-release." >&2 && exit 1) ;
-	@. $(RELEASE_SUPPORT) ; ! differsFromRelease $(TAG) || (echo "ERROR: current directory differs from tagged $(TAG). make [minor,major,patch]-release." ; exit 1)
diff --git a/images/.utils/gitlab-ci.yaml b/images/.utils/gitlab-ci.yaml
index 1cadcf0d2..cdb619a81 100644
--- a/images/.utils/gitlab-ci.yaml
+++ b/images/.utils/gitlab-ci.yaml
@@ -8,61 +8,49 @@
           - synadm
           - query-exposer
 
-container-build-release:
+earthly:
   stage: build
+  image: docker.io/earthly/earthly:v0.7.17
   extends: .container-matrix
-  image:
-    name: quay.io/containers/podman:v4.6.1
-    entrypoint: [""]
+  variables:
+    DOCKER_HOST: tcp://docker:2375
+    FORCE_COLOR: 1
+    EARTHLY_EXEC_CMD: "/bin/sh"
+    EARTHLY_SERVER_ADDRESS: localhost
+    EARTHLY_GRPC_ADDRESS: localhost
+  services:
+    - docker:dind
   before_script:
-    - podman login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
+      - docker run --privileged --rm tonistiigi/binfmt --install all
+      - earthly config global.disable_analytics true
+      - earthly config global.disable_log_sharing true
+      - earthly account logout
+      - earthly bootstrap
+      - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
   script:
-    -  export $(cat "${CI_PROJECT_DIR}/images/${IMAGE}/.release")
-    -  podman image build --pull
-      --label "org.opencontainers.image.source=$CI_PROJECT_URL/-/tree/$CI_COMMIT_SHA/images/${IMAGE}"
-      --label "org.opencontainers.image.revision=$CI_COMMIT_SHA"
-      --label "org.opencontainers.image.title=${IMAGE}"
-      --format=docker
-      --timestamp="$(date -d "${CI_COMMIT_TIMESTAMP}" +%s)"
-      --tag "quay.io/shivering-isles/${IMAGE}:${CI_COMMIT_SHORT_SHA}"
-      "${CI_PROJECT_DIR}/images/${IMAGE}"
-    - podman push "quay.io/shivering-isles/${IMAGE}:${CI_COMMIT_SHORT_SHA}" "quay.io/shivering-isles/${IMAGE}:${release}"
-    - podman push "quay.io/shivering-isles/${IMAGE}:${CI_COMMIT_SHORT_SHA}" "quay.io/shivering-isles/${IMAGE}:latest"
+    - cd images/${IMAGE}
+    - |
+      if [ -n "$CI_OCI_CACHE" ]; then
+        export ARGS="${ARGS} --remote-cache=$CI_OCI_CACHE"
+      fi
+    - |
+      if [ $CI_COMMIT_BRANCH = $CI_DEFAULT_BRANCH ]; then
+        export BUILD_ARGS="${BUILD_ARGS} --latest=true"
+      else
+        export BUILD_ARGS="${BUILD_ARGS} --tag=$CI_COMMIT_REF_SLUG --latest=false"
+      fi
+    - earthly --ci --allow-privileged --push ${ARGS} +container --registry=quay.io/shivering-isles/${IMAGE} ${BUILD_ARGS}
+  tags:
+    - privileged
   rules:
     - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"'
       changes:
         - images/${IMAGE}/.release
     - if: '$FORCE_BUILD_IMAGE == $IMAGE'
-  tags:
-    - hetzner
-
-
-container-build-dev:
-  stage: build
-  extends: .container-matrix
-  image:
-    name: quay.io/containers/podman:v4.6.1
-    entrypoint: [""]
-  before_script:
-    - podman login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
-  script:
-    -  podman image build --pull
-      --label "org.opencontainers.image.source=$CI_PROJECT_URL/-/tree/$CI_COMMIT_SHA/images/${IMAGE}"
-      --label "org.opencontainers.image.revision=$CI_COMMIT_SHA"
-      --label "org.opencontainers.image.title=${IMAGE}"
-      --label "quay.expires-after=12w"
-      --format=docker
-      --timestamp="$(date -d "${CI_COMMIT_TIMESTAMP}" +%s)"
-      --tag "quay.io/shivering-isles/${IMAGE}:${CI_COMMIT_SHORT_SHA}"
-      "${CI_PROJECT_DIR}/images/${IMAGE}"
-    - podman push "quay.io/shivering-isles/${IMAGE}:${CI_COMMIT_SHORT_SHA}" "quay.io/shivering-isles/${IMAGE}:${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA}"
-    - podman push "quay.io/shivering-isles/${IMAGE}:${CI_COMMIT_SHORT_SHA}" "quay.io/shivering-isles/${IMAGE}:${CI_COMMIT_REF_SLUG}"
-  rules:
     - if: '$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"'
       changes:
         paths:
           - images/${IMAGE}/**/*
           - images/.utils/*
+          - images/mirror/*
         compare_to: main
-  tags:
-    - hetzner
diff --git a/images/demo/Dockerfile b/images/demo/Dockerfile
deleted file mode 100644
index 1348723e5..000000000
--- a/images/demo/Dockerfile
+++ /dev/null
@@ -1,3 +0,0 @@
-FROM quay.io/fedora/fedora:38
-
-RUN echo "Hello world"
diff --git a/images/demo/Earthfile b/images/demo/Earthfile
new file mode 100644
index 000000000..d5a2a3d7a
--- /dev/null
+++ b/images/demo/Earthfile
@@ -0,0 +1,6 @@
+VERSION 0.7
+
+container:
+    FROM ../mirror+fedora
+
+    RUN echo "Hello world"
diff --git a/images/demo/Makefile b/images/demo/Makefile
deleted file mode 100644
index ef36bf84f..000000000
--- a/images/demo/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-include ../.utils/container-build.mk
-include ../../utils/help.mk
-
-pre-build:
-	@echo do some stuff before the docker build
-
-post-build:
-	@echo do some stuff after the docker build
diff --git a/images/dovecot/.release b/images/dovecot/.release
index 27146f86d..ca0bf5442 100644
--- a/images/dovecot/.release
+++ b/images/dovecot/.release
@@ -1 +1 @@
-release=0.2.2
+release=0.3.0
\ No newline at end of file
diff --git a/images/dovecot/Dockerfile b/images/dovecot/Dockerfile
deleted file mode 100644
index 1f22d8b4e..000000000
--- a/images/dovecot/Dockerfile
+++ /dev/null
@@ -1,47 +0,0 @@
-FROM docker.io/library/alpine:3.18.3
-
-# Update base system
-RUN apk update
-RUN apk add --no-cache ca-certificates
-RUN update-ca-certificates
-
-# Disable Dovecot TLS during installation to prevent key from being pregenerated
-RUN mkdir -p /etc/dovecot && echo "ssl = no" > /etc/dovecot/local.conf
-
-# Install all alpine dovecot packages (except documentation and development files)
-RUN apk add --no-cache \
-	dovecot \
-	dovecot-pigeonhole-plugin \
-	dovecot-lmtpd
-
-COPY config/dovecot.conf /etc/dovecot/
-
-ENV USER=vmail
-ENV UID=5000
-ENV GID=5000
-
-RUN addgroup --gid "$GID" "$USER" \
-    && adduser \
-    --disabled-password \
-    --gecos "" \
-    --home "$(pwd)" \
-    --ingroup "$USER" \
-    --no-create-home \
-    --uid "$UID" \
-    "$USER"
-
-RUN mkdir /srv/mail && chown 5000:5000 /srv/mail
-
-VOLUME /srv/mail
-
-#    24: LMTP
-#   110: POP3 (StartTLS)
-#   143: IMAP4 (StartTLS)
-#   993: IMAP (SSL, deprecated)
-#   995: POP3 (SSL, deprecated)
-#  4190: ManageSieve (StartTLS)
-#  9090: Metrics (Prometheus compatible)
-# 12345: SASL Auth (for Postfix)
-EXPOSE 24 110 143 993 995 4190 12345
-
-ENTRYPOINT ["/usr/sbin/dovecot", "-F"]
diff --git a/images/dovecot/Earthfile b/images/dovecot/Earthfile
new file mode 100644
index 000000000..343862a34
--- /dev/null
+++ b/images/dovecot/Earthfile
@@ -0,0 +1,58 @@
+VERSION 0.7
+
+
+
+container:
+    FROM ../mirror+alpine
+    ARG registry=quay.io/shivering-isles/dovecot
+    COPY .release ./
+    ARG tag=$(awk -F'=' '$1 == "release" {print $2}' .release)
+    ARG latest=false
+    # Update base system
+    RUN apk add --no-cache ca-certificates
+    RUN update-ca-certificates
+
+    # Disable Dovecot TLS during installation to prevent key from being pregenerated
+    RUN mkdir -p /etc/dovecot && echo "ssl = no" > /etc/dovecot/local.conf
+
+    # Install all alpine dovecot packages (except documentation and development files)
+    RUN apk add --no-cache \
+        dovecot \
+        dovecot-pigeonhole-plugin \
+        dovecot-lmtpd
+
+    COPY config/dovecot.conf /etc/dovecot/
+
+    ENV USER=vmail
+    ENV UID=5000
+    ENV GID=5000
+
+    RUN addgroup --gid "$GID" "$USER" \
+        && adduser \
+        --disabled-password \
+        --gecos "" \
+        --home "$(pwd)" \
+        --ingroup "$USER" \
+        --no-create-home \
+        --uid "$UID" \
+        "$USER"
+
+    RUN mkdir /srv/mail && chown 5000:5000 /srv/mail
+
+    VOLUME /srv/mail
+
+    #    24: LMTP
+    #   110: POP3 (StartTLS)
+    #   143: IMAP4 (StartTLS)
+    #   993: IMAP (SSL, deprecated)
+    #   995: POP3 (SSL, deprecated)
+    #  4190: ManageSieve (StartTLS)
+    #  9090: Metrics (Prometheus compatible)
+    # 12345: SASL Auth (for Postfix)
+    EXPOSE 24 110 143 993 995 4190 12345
+
+    ENTRYPOINT ["/usr/sbin/dovecot", "-F"]
+    IF [ $latest = "true" ]
+        SAVE IMAGE --push ${registry}:latest
+    END
+    SAVE IMAGE --push ${registry}:${tag}
diff --git a/images/dovecot/Makefile b/images/dovecot/Makefile
deleted file mode 100644
index d433bc8ba..000000000
--- a/images/dovecot/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-include ../.utils/container-build.mk
-include ../../utils/help.mk
diff --git a/images/koolbox/.release b/images/koolbox/.release
index 1262b0cb1..e34b250c3 100644
--- a/images/koolbox/.release
+++ b/images/koolbox/.release
@@ -1 +1 @@
-release=0.4.3
+release=0.5.0
diff --git a/images/koolbox/Earthfile b/images/koolbox/Earthfile
new file mode 100644
index 000000000..546cd0129
--- /dev/null
+++ b/images/koolbox/Earthfile
@@ -0,0 +1,13 @@
+VERSION 0.7
+
+container:
+    FROM ../mirror+alpine
+    ARG registry=quay.io/shivering-isles/koolbox
+    COPY .release ./
+    ARG tag=$(awk -F'=' '$1 == "release" {print $2}' .release)
+    ARG latest=false
+    FROM DOCKERFILE --platform=linux/amd64 -f "./Dockerfile" "./"
+    IF [ $latest = "true" ]
+        SAVE IMAGE --push ${registry}:latest
+    END
+    SAVE IMAGE --push ${registry}:${tag}
\ No newline at end of file
diff --git a/images/mirror/.skip-earthly b/images/mirror/.skip-earthly
new file mode 100644
index 000000000..e69de29bb
diff --git a/images/mirror/Earthfile b/images/mirror/Earthfile
new file mode 100644
index 000000000..0c164dd6d
--- /dev/null
+++ b/images/mirror/Earthfile
@@ -0,0 +1,25 @@
+VERSION 0.7
+
+MIRROR:
+    COMMAND
+    ARG image
+    FROM ${image}
+    SAVE IMAGE --cache-hint
+
+distroless-static-debug:
+    DO +MIRROR --image=gcr.io/distroless/static:debug-nonroot
+
+distroless-static:
+    DO +MIRROR --image=gcr.io/distroless/static:nonroot
+
+golang:
+    DO +MIRROR --image=docker.io/library/golang:1.20.5-alpine
+
+alpine:
+    DO +MIRROR --image=docker.io/library/alpine:3.18.3
+
+trivy:
+    DO +MIRROR --image=docker.io/aquasec/trivy:0.37.3
+
+fedora:
+    DO +MIRROR --image=quay.io/fedora/fedora:38
\ No newline at end of file
diff --git a/images/postfix/.release b/images/postfix/.release
index 148b60db7..e34b250c3 100644
--- a/images/postfix/.release
+++ b/images/postfix/.release
@@ -1 +1 @@
-release=0.4.6
+release=0.5.0
diff --git a/images/postfix/Dockerfile b/images/postfix/Dockerfile
deleted file mode 100644
index 6dee7ab03..000000000
--- a/images/postfix/Dockerfile
+++ /dev/null
@@ -1,31 +0,0 @@
-FROM docker.io/library/alpine:3.18.3 as dhparam
-
-RUN apk add --no-cache openssl
-
-RUN mkdir -p /etc/postfix
-RUN openssl dhparam -out /etc/postfix/postfix_dhparams.pem 2048
-
-FROM docker.io/library/alpine:3.18.3
-
-# Install pre-requirements
-RUN apk add --no-cache ca-certificates rsyslog supervisor
-RUN update-ca-certificates
-
-RUN apk add --no-cache postfix cyrus-sasl cyrus-sasl-login
-
-RUN mkdir /var/spool/postfix/etc && echo "smtp		25/tcp		mail		# Simple Mail Transfer" > /var/spool/postfix/etc/services
-
-COPY config/main.cf /etc/postfix/
-COPY config/master.cf /etc/postfix/
-COPY docker/supervisord.conf /etc/
-COPY docker/rsyslog.conf /etc/
-COPY docker/start.sh /usr/local/libexec/start.sh
-RUN chmod +x /usr/local/libexec/start.sh
-COPY --from=dhparam --chown=postfix:postfix /etc/postfix/postfix_dhparams.pem /etc/postfix/postfix_dhparams.pem
-#    25: SMTP (Server2Server)
-#   465: SUBMISSIONS (SSL)
-#   587: SMTP (StartTLS)
-# 10025: Postscreen for HAProxy
-EXPOSE 25 465 587 10025
-
-ENTRYPOINT [ "sh" , "/usr/local/libexec/start.sh" ]
diff --git a/images/postfix/Earthfile b/images/postfix/Earthfile
new file mode 100644
index 000000000..12bb2f2d2
--- /dev/null
+++ b/images/postfix/Earthfile
@@ -0,0 +1,44 @@
+VERSION 0.7
+
+all:
+    BUILD +container
+
+dhparams:
+    FROM ../mirror+alpine
+    RUN apk add --no-cache openssl
+    RUN openssl dhparam -out ./postfix_dhparams.pem 2048 2>/dev/null
+    SAVE ARTIFACT ./postfix_dhparams.pem
+
+container:
+    FROM ../mirror+alpine
+    ARG registry=quay.io/shivering-isles/postfix
+    COPY .release ./
+    ARG tag=$(awk -F'=' '$1 == "release" {print $2}' .release)
+    ARG latest=false
+
+    # Install pre-requirements
+    RUN apk add --no-cache ca-certificates rsyslog supervisor
+    RUN update-ca-certificates
+
+    RUN apk add --no-cache postfix cyrus-sasl cyrus-sasl-login
+
+    RUN mkdir /var/spool/postfix/etc && echo "smtp		25/tcp		mail		# Simple Mail Transfer" > /var/spool/postfix/etc/services
+
+    COPY config/main.cf /etc/postfix/
+    COPY config/master.cf /etc/postfix/
+    COPY docker/supervisord.conf /etc/
+    COPY docker/rsyslog.conf /etc/
+    COPY docker/start.sh /usr/local/libexec/start.sh
+    RUN chmod +x /usr/local/libexec/start.sh
+    COPY --chown=postfix:postfix +dhparams/postfix_dhparams.pem /etc/postfix/postfix_dhparams.pem
+    #    25: SMTP (Server2Server)
+    #   465: SUBMISSIONS (SSL)
+    #   587: SMTP (StartTLS)
+    # 10025: Postscreen for HAProxy
+    EXPOSE 25 465 587 10025
+
+    ENTRYPOINT [ "sh" , "/usr/local/libexec/start.sh" ]
+    IF [ $latest = "true" ]
+        SAVE IMAGE --push ${registry}:latest
+    END
+    SAVE IMAGE --push ${registry}:${tag}
\ No newline at end of file
diff --git a/images/postfix/Makefile b/images/postfix/Makefile
deleted file mode 100644
index d433bc8ba..000000000
--- a/images/postfix/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-include ../.utils/container-build.mk
-include ../../utils/help.mk
diff --git a/images/query-exposer/.release b/images/query-exposer/.release
index 1ff7e5463..58187b962 100644
--- a/images/query-exposer/.release
+++ b/images/query-exposer/.release
@@ -1 +1 @@
-release=0.1.0
\ No newline at end of file
+release=0.2.0
\ No newline at end of file
diff --git a/images/query-exposer/Dockerfile b/images/query-exposer/Dockerfile
deleted file mode 100644
index 03a24d728..000000000
--- a/images/query-exposer/Dockerfile
+++ /dev/null
@@ -1,16 +0,0 @@
-FROM docker.io/library/golang:1.21.0 as build
-
-WORKDIR /go/src/app
-COPY vendor ./vendor
-COPY go.* main.go .
-
-RUN CGO_ENABLED=0 go build -mod=vendor -o /go/bin/query-exposer
-
-FROM gcr.io/distroless/static:latest
-
-COPY --from=build /go/bin/query-exposer /query-exposer
-
-USER 1000
-
-ENTRYPOINT ["/query-exposer"]
-
diff --git a/images/query-exposer/Earthfile b/images/query-exposer/Earthfile
new file mode 100644
index 000000000..d3e5106f2
--- /dev/null
+++ b/images/query-exposer/Earthfile
@@ -0,0 +1,38 @@
+VERSION 0.7
+FROM ../mirror+golang
+WORKDIR /go-workdir
+
+IMPORT ../.utils AS image
+
+all:
+    BUILD +lint
+    BUILD +scan
+    BUILD +container
+
+code:
+    COPY vendor ./vendor
+    COPY go.* main.go .
+    ENV CGO_ENABLED=0
+
+build:
+    FROM +code
+    RUN go build -mod=vendor -o output/query-exposer
+    SAVE ARTIFACT output/query-exposer AS LOCAL local-output/go-query-exposer
+
+container:
+    COPY .release ./
+    ARG tag=$(awk -F'=' '$1 == "release" {print $2}' .release)
+    FROM ../mirror+distroless-static
+    ARG registry=quay.io/shivering-isles/query-exposer
+    ARG latest=false
+    COPY +build/query-exposer /
+    ENTRYPOINT ["/query-exposer"]
+    SAVE IMAGE --push ${registry}:${tag}
+
+scan:
+    DO image+SCAN
+
+lint:
+    FROM +code
+    RUN go vet $(go list ./... | grep -v vendor)
+    RUN go fmt $(go list ./... | grep -v vendor)
diff --git a/images/query-exposer/Makefile b/images/query-exposer/Makefile
deleted file mode 100644
index d433bc8ba..000000000
--- a/images/query-exposer/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-include ../.utils/container-build.mk
-include ../../utils/help.mk
diff --git a/images/synadm/.release b/images/synadm/.release
index 9990762bd..7f1bdeb40 100644
--- a/images/synadm/.release
+++ b/images/synadm/.release
@@ -1 +1 @@
-release=0.2.0
+release=0.3.0
diff --git a/images/synadm/Earthfile b/images/synadm/Earthfile
new file mode 100644
index 000000000..fc4be6bde
--- /dev/null
+++ b/images/synadm/Earthfile
@@ -0,0 +1,13 @@
+VERSION 0.7
+
+container:
+    FROM ../mirror+alpine
+    ARG registry=quay.io/shivering-isles/synadm
+    COPY .release ./
+    ARG tag=$(awk -F'=' '$1 == "release" {print $2}' .release)
+    ARG latest=false
+    FROM DOCKERFILE --platform=linux/amd64 -f "./Dockerfile" "./"
+    IF [ $latest = "true" ]
+        SAVE IMAGE --push ${registry}:latest
+    END
+    SAVE IMAGE --push ${registry}:${tag}
\ No newline at end of file
diff --git a/renovate.json b/renovate.json
index 8541d3d3b..6795941c4 100644
--- a/renovate.json
+++ b/renovate.json
@@ -24,6 +24,14 @@
     "fileMatch": ["\.gitlab-ci\.yml$", "gitlab-ci\.yaml$"]
   },
   "regexManagers": [
+    {
+      "fileMath": ["Earthfile$"],
+      "matchStrings": [
+          "FROM\\s+(?<depName>(?!\\+)[a-z0-9./-]+):?(?<currentValue>[a-z0-9-.]+)?@?(?<currentDigest>sha256:[a-f0-9]+)?"
+      ],
+      "datasourceTemplate": "docker",
+      "versioningTemplate": "docker"
+    },
     {
       "fileMatch": ["\\.yaml$"],
       "matchStrings": [
-- 
GitLab