aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat
-rw-r--r--.dockerignore15+0 −15
-rw-r--r--.github/workflows/build.yml139+8 −131
-rw-r--r--.gitignore1+0 −1
-rw-r--r--README.md24+14 −10
-rw-r--r--REUSE.toml2+0 −2
-rw-r--r--Taskfile.yml96+94 −2
-rw-r--r--charts/mirum/Chart.yaml10+0 −10
-rw-r--r--charts/mirum/templates/_helpers.tpl40+0 −40
-rw-r--r--charts/mirum/templates/server-deployment.yaml142+0 −142
-rw-r--r--charts/mirum/templates/server-httproute.yaml26+0 −26
-rw-r--r--charts/mirum/templates/server-service.yaml23+0 −23
-rw-r--r--charts/mirum/templates/server-tcproute.yaml22+0 −22
-rw-r--r--charts/mirum/templates/worker-deployment.yaml87+0 −87
-rw-r--r--charts/mirum/values.yaml75+0 −75
-rw-r--r--cmd/mirum-server/Dockerfile20+0 −20
-rw-r--r--cmd/mirum-worker/Dockerfile26+0 −26
-rw-r--r--mise.lock14+14 −0
-rw-r--r--mise.toml6+2 −4
-rw-r--r--nfpm.yaml6+3 −3
-rw-r--r--packaging/apt-ftparchive.conf29+29 −0
20 files changed, 164 insertions, 639 deletions
diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
--- a/.dockerignore
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-.git
-.github
-.task
-build
-cmd/mirum-agent/.zig-cache
-cmd/mirum-agent/zig-out
-cmd/mirum-agent/zig-pkg
-cmd/mirum-server/apipb
-cmd/mirum-server/static
-cmd/mirum-server/web/gen
-cmd/mirum-server/web/node_modules
-internal/protocol/wirepb
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7e1bd0e..99da313 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -18,11 +18,6 @@ jobs:
build:
name: Build and publish Nightly
runs-on: ubuntu-latest
- concurrency:
- group: >-
- package-publish-mirum-${{ github.ref == 'refs/heads/main' && 'nightly'
- || startsWith(github.ref, 'refs/tags/v') && 'stable' || github.ref }}
- cancel-in-progress: false
permissions:
contents: write
steps:
@@ -45,7 +40,6 @@ jobs:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
APK_PRIVATE_KEY: ${{ secrets.APK_PRIVATE_KEY }}
- PACKAGE_KEY_VERSION: ${{ vars.PACKAGE_KEY_VERSION }}
- name: Lint
run: task lint
@@ -53,17 +47,6 @@ jobs:
- name: Tests
run: task test
- - name: Upload container binaries
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
- with:
- name: container-binaries
- path: |
- build/mirum-server-linux-amd64
- build/mirum-server-linux-arm64
- build/mirum-worker-linux-amd64
- build/mirum-worker-linux-arm64
- if-no-files-found: error
-
- name: Publish
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
run: |
@@ -71,123 +54,17 @@ jobs:
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
. build/dist/build.env
task publish:release CHANNEL=$CHANNEL VERSION=$VERSION
- mise run publish -- \
- --service mirum \
- --channel "$CHANNEL" \
- --input build/dist \
- deb rpm apk
+ task publish:repos \
+ CHANNEL=$CHANNEL \
+ S3_BUCKET=${{ vars.S3_BUCKET }} \
+ S3_PUBLIC_URL=${{ vars.S3_PUBLIC_URL }} \
+ S3_PROVIDER="${{ vars.S3_PROVIDER || 'Other' }}" \
+ S3_REGION=${{ vars.S3_REGION }} \
+ S3_ENDPOINT=${{ vars.S3_ENDPOINT }} \
+ GPG_KEY_ID=${{ vars.GPG_KEY_ID }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
- GPG_KEY_ID: ${{ vars.GPG_KEY_ID }}
- APK_PRIVATE_KEY: ${{ secrets.APK_PRIVATE_KEY }}
- PACKAGE_KEY_VERSION: ${{ vars.PACKAGE_KEY_VERSION }}
- S3_BUCKET: ${{ vars.S3_BUCKET }}
- S3_ENDPOINT: ${{ vars.S3_ENDPOINT }}
- S3_PUBLIC_URL: ${{ vars.S3_PUBLIC_URL }}
S3_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
S3_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
-
- oci:
- name: OCI artifacts
- needs: [build]
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
-
- - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3
- with:
- version: 2026.7.5
- experimental: true
- install: false
-
- - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
- with:
- name: container-binaries
- path: .container
-
- - uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
-
- - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
-
- - name: Determine artifact version
- id: artifact
- shell: bash
- run: |
- base_version=$(cat VERSION)
- if [[ "$GITHUB_REF" == refs/heads/main ]]; then
- version="$base_version-nightly.$(git log -1 --format=%ct)"
- elif [[ "$GITHUB_REF" == refs/tags/v* ]]; then
- version="${GITHUB_REF_NAME#v}"
- if [[ "$version" != "$base_version" ]]; then
- echo "Tag version $version does not match VERSION $base_version" >&2
- exit 1
- fi
- else
- version="$base_version-pr.$GITHUB_RUN_NUMBER"
- fi
- echo "version=$version" >> "$GITHUB_OUTPUT"
-
- - name: Log in to GHCR
- if: github.event_name != 'pull_request'
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Log Helm in to GHCR
- if: github.event_name != 'pull_request'
- env:
- GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: |
- printf '%s' "$GHCR_TOKEN" | mise x helm@4.1.1 -- \
- helm registry login ghcr.io --username "$GITHUB_ACTOR" --password-stdin
-
- - name: Build and publish OCI artifacts
- shell: bash
- run: |
- version="${{ steps.artifact.outputs.version }}"
- image_output=()
- chart_output=()
-
- if [[ "${{ github.event_name }}" != pull_request ]]; then
- image_output+=(--push)
- chart_output+=(--push "oci://ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/charts")
- fi
-
- for service in server worker; do
- image="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/mirum-$service"
- tags=(
- --tag "$image:sha-$GITHUB_SHA"
- --tag "$image:$version"
- )
- labels=(
- --label "org.opencontainers.image.revision=$GITHUB_SHA"
- --label "org.opencontainers.image.source=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
- --label "org.opencontainers.image.version=$version"
- )
-
- if [[ "$GITHUB_REF" == refs/heads/main ]]; then
- tags+=(--tag "$image:nightly")
- elif [[ "$GITHUB_REF" == refs/tags/v* ]]; then
- tags+=(--tag "$image:latest")
- fi
-
- mise run container -- \
- --context . \
- --file "cmd/mirum-$service/Dockerfile" \
- --platform linux/amd64,linux/arm64 \
- --cache-scope "mirum-$service" \
- "${tags[@]}" "${labels[@]}" "${image_output[@]}"
- done
-
- mise run chart -- \
- --chart charts/mirum \
- --version "$version" \
- --app-version "$version" \
- "${chart_output[@]}"
diff --git a/.gitignore b/.gitignore
index 437dc77..149195c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
/dev
/build
-/.container
/.task
mise.local.toml
mise.*.local.toml
diff --git a/README.md b/README.md
index a9f4640..8cb272c 100644
--- a/README.md
+++ b/README.md
@@ -139,8 +139,8 @@ Please note that the project is in its infancy and is **not** intended for produ
```bash
sudo apt install curl gnupg
-curl -fsSL https://pkg.dimidiumlabs.io/packages.gpg | sudo gpg --dearmor -o /usr/share/keyrings/dimidiumlabs.gpg
-echo "deb [signed-by=/usr/share/keyrings/dimidiumlabs.gpg] https://pkg.dimidiumlabs.io/mirum/apt/ nightly main" | sudo tee /etc/apt/sources.list.d/mirum.list
+curl -fsSL https://dl.mirum.dev/public.gpg | sudo gpg --dearmor -o /usr/share/keyrings/mirum.gpg
+echo "deb [signed-by=/usr/share/keyrings/mirum.gpg] https://dl.mirum.dev/apt/ nightly main" | sudo tee /etc/apt/sources.list.d/mirum.list
sudo apt update && sudo apt install mirum
# Start the server
@@ -154,10 +154,10 @@ sudo systemctl enable --now mirum-worker@default
```bash
# DNF5 (Fedora 41+, RHEL 10+)
-sudo dnf config-manager addrepo --from-repofile=https://pkg.dimidiumlabs.io/mirum/rpm/nightly/mirum-nightly.repo
+sudo dnf config-manager addrepo --from-repofile=https://dl.mirum.dev/rpm/nightly/mirum-nightly.repo
# DNF4 (Fedora 40 and older, RHEL 8/9)
-sudo curl -o /etc/yum.repos.d/mirum-nightly.repo https://pkg.dimidiumlabs.io/mirum/rpm/nightly/mirum-nightly.repo
+sudo curl -o /etc/yum.repos.d/mirum-nightly.repo https://dl.mirum.dev/rpm/nightly/mirum-nightly.repo
sudo dnf install mirum
@@ -171,8 +171,8 @@ sudo systemctl enable --now mirum-worker@default
**openSUSE:**
```bash
-sudo rpm --import https://pkg.dimidiumlabs.io/packages.gpg
-sudo zypper addrepo https://pkg.dimidiumlabs.io/mirum/rpm/nightly/ mirum-nightly
+sudo rpm --import https://dl.mirum.dev/public.gpg
+sudo zypper addrepo https://dl.mirum.dev/rpm/nightly/ mirum-nightly
sudo zypper refresh
sudo zypper install mirum
@@ -185,11 +185,15 @@ sudo systemctl enable --now mirum-worker@default
**Alpine:**
+No repository yet — grab the signing key and the signed `.apk` from the nightly
+release:
+
```sh
-sudo wget -O /etc/apk/keys/packages.0001.rsa.pub https://pkg.dimidiumlabs.io/keys/packages.0001.rsa.pub
-echo "https://pkg.dimidiumlabs.io/mirum/apk/nightly" | sudo tee -a /etc/apk/repositories
-sudo apk update
-sudo apk add mirum
+sudo wget -O /etc/apk/keys/mirum.rsa.pub https://dl.mirum.dev/mirum.rsa.pub
+
+# Download the .apk for your arch from
+# https://github.com/dimidiumlabs/mirum/releases/tag/nightly
+sudo apk add ./mirum_<version>_<arch>.apk
# Start the server
sudo rc-update add mirum-server default
diff --git a/REUSE.toml b/REUSE.toml
index 708bc13..850dd72 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -14,7 +14,6 @@ path = [
"mise.lock",
"packaging/dl/*",
"packaging/logo.svg",
- "charts/mirum/templates/*",
"buf.*",
]
SPDX-FileCopyrightText = "2026 Nikolay Govorov"
@@ -30,7 +29,6 @@ SPDX-License-Identifier = "CC-BY-3.0"
[[annotations]]
path = [
"README.md",
- "charts/mirum/README.md",
"docs/**.md",
]
SPDX-FileCopyrightText = "2026 Nikolay Govorov"
diff --git a/Taskfile.yml b/Taskfile.yml
index 8e9b060..f803a40 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -250,12 +250,104 @@ tasks:
--version "{{.VERSION}}" \
--arch "$arch" \
--output "{{.DIST_DIR}}" \
+ --apk-public-key mirum.rsa.pub \
$formats
rm -rf {{.BUILD_DIR}}/tmp
done
printf 'VERSION={{.VERSION}}\nCHANNEL={{.CHANNEL}}\n' > {{.DIST_DIR}}/build.env
+ publish:repos:
+ desc: Publish packages to APT and RPM repositories on S3
+ requires:
+ vars:
+ [
+ CHANNEL,
+ S3_BUCKET,
+ S3_PUBLIC_URL,
+ S3_PROVIDER,
+ S3_REGION,
+ S3_ENDPOINT,
+ GPG_KEY_ID,
+ ]
+ cmds:
+ - |
+ set -e
+ export GNUPGHOME=$(mktemp -d)
+ RCLONE_CONF=$(mktemp)
+ chmod 700 "$GNUPGHOME"
+ cleanup() { rm -rf "$GNUPGHOME" "$RCLONE_CONF"; }
+ trap cleanup EXIT
+
+ cat > "$RCLONE_CONF" << EOF
+ [s3]
+ type = s3
+ provider = {{.S3_PROVIDER}}
+ access_key_id = ${S3_ACCESS_KEY_ID}
+ secret_access_key = ${S3_SECRET_ACCESS_KEY}
+ region = {{.S3_REGION}}
+ endpoint = {{.S3_ENDPOINT}}
+ EOF
+ export RCLONE_CONFIG="$RCLONE_CONF"
+
+ printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" --import
+ echo "allow-loopback-pinentry" >> "$GNUPGHOME/gpg-agent.conf"
+ gpgconf --kill gpg-agent
+
+ # Upload static files
+ gpg --export --armor "{{.GPG_KEY_ID}}" > "$GNUPGHOME/public.gpg"
+ rclone copyto "$GNUPGHOME/public.gpg" "s3:{{.S3_BUCKET}}/public.gpg"
+ rclone copy packaging/dl/ "s3:{{.S3_BUCKET}}/"
+
+ if [ -f "{{.DIST_DIR}}/mirum.rsa.pub" ]; then
+ rclone copyto "{{.DIST_DIR}}/mirum.rsa.pub" "s3:{{.S3_BUCKET}}/mirum.rsa.pub"
+ fi
+
+ # APT repository
+ CHANNEL={{.CHANNEL}}
+ mkdir -p /tmp/apt-cache apt-repo
+ rclone copy "s3:{{.S3_BUCKET}}/apt/" apt-repo/
+
+ for ch in stable nightly; do
+ mkdir -p apt-repo/pool/$ch
+ for arch in {{.LINUX_PKG_TARGETS}}; do
+ mkdir -p apt-repo/dists/$ch/main/binary-$arch
+ done
+ done
+ cp {{.DIST_DIR}}/*.deb apt-repo/pool/$CHANNEL/
+
+ cd apt-repo
+ apt-ftparchive generate "$(pwd)/../packaging/apt-ftparchive.conf"
+ apt-ftparchive \
+ -o APT::FTPArchive::Release::Codename=$CHANNEL \
+ -o APT::FTPArchive::Release::Components=main \
+ -o APT::FTPArchive::Release::Architectures="{{.LINUX_PKG_TARGETS}}" \
+ release dists/$CHANNEL/ > dists/$CHANNEL/Release
+ gpg --default-key="{{.GPG_KEY_ID}}" --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" -abs -o dists/$CHANNEL/Release.gpg dists/$CHANNEL/Release
+ gpg --default-key="{{.GPG_KEY_ID}}" --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" --clearsign -o dists/$CHANNEL/InRelease dists/$CHANNEL/Release
+ cd ..
+ rclone copy apt-repo/ "s3:{{.S3_BUCKET}}/apt/" --progress
+
+ # RPM repository
+ mkdir -p rpm-repo
+ rclone copy "s3:{{.S3_BUCKET}}/rpm/$CHANNEL/" rpm-repo/
+
+ cp {{.DIST_DIR}}/*.rpm rpm-repo/
+
+ createrepo_c --update rpm-repo/
+ gpg --default-key="{{.GPG_KEY_ID}}" --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" --detach-sign --armor rpm-repo/repodata/repomd.xml
+
+ cat > rpm-repo/mirum-${CHANNEL}.repo << REPOEOF
+ [mirum-${CHANNEL}]
+ name=Mirum ${CHANNEL}
+ gpgkey={{.S3_PUBLIC_URL}}/public.gpg
+ baseurl={{.S3_PUBLIC_URL}}/rpm/${CHANNEL}/
+ enabled=1
+ gpgcheck=1
+ REPOEOF
+
+ rclone copy rpm-repo/ "s3:{{.S3_BUCKET}}/rpm/$CHANNEL/" --progress
+
publish:release:
desc: Create or update a GitHub Release
requires:
@@ -275,11 +367,11 @@ tasks:
done
fi
- gh release create "$TAG" {{.DIST_DIR}}/*.deb {{.DIST_DIR}}/*.rpm {{.DIST_DIR}}/*.apk {{.DIST_DIR}}/*.tar.gz {{.DIST_DIR}}/*.zip {{.DIST_DIR}}/SHA256SUMS \
+ gh release create "$TAG" {{.DIST_DIR}}/*.deb {{.DIST_DIR}}/*.rpm {{.DIST_DIR}}/*.apk {{.DIST_DIR}}/*.rsa.pub {{.DIST_DIR}}/*.tar.gz {{.DIST_DIR}}/*.zip {{.DIST_DIR}}/SHA256SUMS \
--title "$NAME" \
$( [ "{{.CHANNEL}}" = "nightly" ] && echo "--prerelease" ) \
--notes "**Version**: {{.VERSION}}" \
- || gh release upload "$TAG" {{.DIST_DIR}}/*.deb {{.DIST_DIR}}/*.rpm {{.DIST_DIR}}/*.apk {{.DIST_DIR}}/*.tar.gz {{.DIST_DIR}}/*.zip {{.DIST_DIR}}/SHA256SUMS --clobber
+ || gh release upload "$TAG" {{.DIST_DIR}}/*.deb {{.DIST_DIR}}/*.rpm {{.DIST_DIR}}/*.apk {{.DIST_DIR}}/*.rsa.pub {{.DIST_DIR}}/*.tar.gz {{.DIST_DIR}}/*.zip {{.DIST_DIR}}/SHA256SUMS --clobber
# Local dev env
devenv:config:
diff --git a/charts/mirum/Chart.yaml b/charts/mirum/Chart.yaml
deleted file mode 100644
--- a/charts/mirum/Chart.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-apiVersion: v2
-type: application
-version: 0.1.0
-
-name: mirum
-home: https://github.com/dimidiumlabs/mirum
-description: Mirum CI server and workers
diff --git a/charts/mirum/templates/_helpers.tpl b/charts/mirum/templates/_helpers.tpl
deleted file mode 100644
--- a/charts/mirum/templates/_helpers.tpl
+++ /dev/null
@@ -1,40 +0,0 @@
-{{/* SPDX-License-Identifier: AGPL-3.0-or-later */}}
-{{/* vim: set filetype=helm: */}}
-{{- define "mirum.name" -}}
-{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-
-{{- define "mirum.fullname" -}}
-{{- if .Values.fullnameOverride -}}
-{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
-{{- else -}}
-{{- printf "%s-%s" .Release.Name (include "mirum.name" .) | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-{{- end -}}
-
-{{- define "mirum.labels" -}}
-helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" }}
-app.kubernetes.io/name: {{ include "mirum.name" . }}
-app.kubernetes.io/instance: {{ .Release.Name }}
-app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
-app.kubernetes.io/managed-by: {{ .Release.Service }}
-{{- end -}}
-
-{{- define "mirum.componentLabels" -}}
-{{ include "mirum.labels" .root }}
-app.kubernetes.io/component: {{ .component }}
-{{- end -}}
-
-{{- define "mirum.selectorLabels" -}}
-app.kubernetes.io/name: {{ include "mirum.name" .root }}
-app.kubernetes.io/instance: {{ .root.Release.Name }}
-app.kubernetes.io/component: {{ .component }}
-{{- end -}}
-
-{{- define "mirum.image" -}}
-{{- if .image.digest -}}
-{{- printf "%s@%s" .image.repository .image.digest -}}
-{{- else -}}
-{{- printf "%s:%s" .image.repository (default .root.Chart.AppVersion .image.tag) -}}
-{{- end -}}
-{{- end -}}
diff --git a/charts/mirum/templates/server-deployment.yaml b/charts/mirum/templates/server-deployment.yaml
deleted file mode 100644
--- a/charts/mirum/templates/server-deployment.yaml
+++ /dev/null
@@ -1,142 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-{{- if and .Values.server.enabled (ne (int .Values.server.replicaCount) 1) }}
-{{- fail "mirum: server.replicaCount must be 1 while the task queue is process-local" }}
-{{- end }}
-{{- if and .Values.server.enabled .Values.server.postgresqlMtls.enabled (not .Values.server.serviceAccountName) }}
-{{- fail "mirum: server.serviceAccountName is required when server.postgresqlMtls.enabled=true" }}
-{{- end }}
-{{- if .Values.server.enabled }}
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: {{ include "mirum.fullname" . }}-server
- labels:
- {{- include "mirum.componentLabels" (dict "root" . "component" "server") | nindent 4 }}
-spec:
- replicas: {{ .Values.server.replicaCount }}
- strategy:
- type: Recreate
- selector:
- matchLabels:
- {{- include "mirum.selectorLabels" (dict "root" . "component" "server") | nindent 6 }}
- template:
- metadata:
- annotations:
- {{- with .Values.server.podAnnotations }}
- {{- toYaml . | nindent 8 }}
- {{- end }}
- labels:
- {{- include "mirum.selectorLabels" (dict "root" . "component" "server") | nindent 8 }}
- {{- with .Values.server.podLabels }}
- {{- toYaml . | nindent 8 }}
- {{- end }}
- spec:
- automountServiceAccountToken: false
- {{- with .Values.server.serviceAccountName }}
- serviceAccountName: {{ . | quote }}
- {{- end }}
- terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
- securityContext:
- runAsNonRoot: true
- runAsUser: 10000
- runAsGroup: 10000
- fsGroup: 10000
- fsGroupChangePolicy: OnRootMismatch
- {{- with .Values.imagePullSecrets }}
- imagePullSecrets:
- {{- toYaml . | nindent 8 }}
- {{- end }}
- containers:
- - name: server
- image: {{ include "mirum.image" (dict "root" . "image" .Values.server.image) | quote }}
- imagePullPolicy: {{ .Values.server.image.pullPolicy }}
- args: ["daemon", "--config=/etc/mirum/secret/config.yaml"]
- securityContext:
- allowPrivilegeEscalation: false
- capabilities:
- drop: [ALL]
- readOnlyRootFilesystem: true
- ports:
- - name: web
- containerPort: {{ .Values.server.webPort }}
- - name: grpc
- containerPort: {{ .Values.server.grpcPort }}
- {{- with .Values.server.extraEnv }}
- env:
- {{- toYaml . | nindent 12 }}
- {{- end }}
- startupProbe:
- tcpSocket: { port: web }
- failureThreshold: 30
- periodSeconds: 2
- readinessProbe:
- tcpSocket: { port: web }
- livenessProbe:
- tcpSocket: { port: web }
- periodSeconds: 20
- resources:
- {{- toYaml .Values.server.resources | nindent 12 }}
- volumeMounts:
- - name: config
- mountPath: /etc/mirum/secret
- readOnly: true
- {{- with .Values.server.grpcTls.existingSecret }}
- - name: grpc-tls
- mountPath: /etc/mirum/grpc-tls
- readOnly: true
- {{- end }}
- {{- if .Values.server.postgresqlMtls.enabled }}
- - name: postgresql-tls
- mountPath: {{ .Values.server.postgresqlMtls.mountPath }}
- readOnly: true
- {{- end }}
- - name: run
- mountPath: /run/mirum-server
- volumes:
- - name: config
- secret:
- secretName: {{ .Values.server.existingSecret }}
- defaultMode: 0440
- {{- with .Values.server.grpcTls.existingSecret }}
- - name: grpc-tls
- secret:
- secretName: {{ . }}
- defaultMode: 0440
- {{- end }}
- {{- if .Values.server.postgresqlMtls.enabled }}
- - name: postgresql-tls
- csi:
- driver: csi.cert-manager.io
- readOnly: true
- volumeAttributes:
- csi.cert-manager.io/issuer-name: {{ required "mirum: server.postgresqlMtls.issuerName is required" .Values.server.postgresqlMtls.issuerName | quote }}
- csi.cert-manager.io/issuer-kind: {{ .Values.server.postgresqlMtls.issuerKind | quote }}
- csi.cert-manager.io/common-name: {{ required "mirum: server.postgresqlMtls.commonName is required" .Values.server.postgresqlMtls.commonName | quote }}
- csi.cert-manager.io/uri-sans: {{ .Values.server.postgresqlMtls.uriSan | quote }}
- csi.cert-manager.io/key-algorithm: "ECDSA"
- csi.cert-manager.io/key-size: "256"
- csi.cert-manager.io/key-encoding: "PKCS8"
- csi.cert-manager.io/key-usages: "digital signature,client auth"
- csi.cert-manager.io/duration: {{ .Values.server.postgresqlMtls.duration | quote }}
- csi.cert-manager.io/renew-before: {{ .Values.server.postgresqlMtls.renewBefore | quote }}
- csi.cert-manager.io/fs-group: {{ .Values.server.postgresqlMtls.fsGroup | quote }}
- {{- end }}
- - name: run
- emptyDir: {}
- {{- with .Values.server.nodeSelector }}
- nodeSelector:
- {{- toYaml . | nindent 8 }}
- {{- end }}
- {{- with .Values.server.affinity }}
- affinity:
- {{- toYaml . | nindent 8 }}
- {{- end }}
- {{- with .Values.server.tolerations }}
- tolerations:
- {{- toYaml . | nindent 8 }}
- {{- end }}
-{{- end }}
-
-# vim: set filetype=helm:
diff --git a/charts/mirum/templates/server-httproute.yaml b/charts/mirum/templates/server-httproute.yaml
deleted file mode 100644
--- a/charts/mirum/templates/server-httproute.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-{{- if and .Values.server.enabled .Values.server.route.enabled }}
-apiVersion: gateway.networking.k8s.io/v1
-kind: HTTPRoute
-metadata:
- name: {{ include "mirum.fullname" . }}
- labels:
- {{- include "mirum.componentLabels" (dict "root" . "component" "server") | nindent 4 }}
-spec:
- {{- with .Values.server.route.parentRefs }}
- parentRefs:
- {{- toYaml . | nindent 4 }}
- {{- end }}
- {{- with .Values.server.route.hostnames }}
- hostnames:
- {{- toYaml . | nindent 4 }}
- {{- end }}
- rules:
- - backendRefs:
- - name: {{ include "mirum.fullname" . }}
- port: {{ .Values.server.webPort }}
-{{- end }}
-
-# vim: set filetype=helm:
diff --git a/charts/mirum/templates/server-service.yaml b/charts/mirum/templates/server-service.yaml
deleted file mode 100644
--- a/charts/mirum/templates/server-service.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-{{- if .Values.server.enabled }}
-apiVersion: v1
-kind: Service
-metadata:
- name: {{ include "mirum.fullname" . }}
- labels:
- {{- include "mirum.componentLabels" (dict "root" . "component" "server") | nindent 4 }}
-spec:
- selector:
- {{- include "mirum.selectorLabels" (dict "root" . "component" "server") | nindent 4 }}
- ports:
- - name: web
- port: {{ .Values.server.webPort }}
- targetPort: web
- - name: grpc
- port: {{ .Values.server.grpcPort }}
- targetPort: grpc
-{{- end }}
-
-# vim: set filetype=helm:
diff --git a/charts/mirum/templates/server-tcproute.yaml b/charts/mirum/templates/server-tcproute.yaml
deleted file mode 100644
--- a/charts/mirum/templates/server-tcproute.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-{{- if and .Values.server.enabled .Values.server.grpcRoute.enabled }}
-apiVersion: gateway.networking.k8s.io/v1
-kind: TCPRoute
-metadata:
- name: {{ include "mirum.fullname" . }}-grpc
- labels:
- {{- include "mirum.componentLabels" (dict "root" . "component" "server") | nindent 4 }}
-spec:
- {{- with .Values.server.grpcRoute.parentRefs }}
- parentRefs:
- {{- toYaml . | nindent 4 }}
- {{- end }}
- rules:
- - backendRefs:
- - name: {{ include "mirum.fullname" . }}
- port: {{ .Values.server.grpcPort }}
-{{- end }}
-
-# vim: set filetype=helm:
diff --git a/charts/mirum/templates/worker-deployment.yaml b/charts/mirum/templates/worker-deployment.yaml
deleted file mode 100644
--- a/charts/mirum/templates/worker-deployment.yaml
+++ /dev/null
@@ -1,87 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-{{- if .Values.worker.enabled }}
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: {{ include "mirum.fullname" . }}-worker
- labels:
- {{- include "mirum.componentLabels" (dict "root" . "component" "worker") | nindent 4 }}
-spec:
- replicas: {{ .Values.worker.replicaCount }}
- selector:
- matchLabels:
- {{- include "mirum.selectorLabels" (dict "root" . "component" "worker") | nindent 6 }}
- template:
- metadata:
- annotations:
- {{- with .Values.worker.podAnnotations }}
- {{- toYaml . | nindent 8 }}
- {{- end }}
- labels:
- {{- include "mirum.selectorLabels" (dict "root" . "component" "worker") | nindent 8 }}
- {{- with .Values.worker.podLabels }}
- {{- toYaml . | nindent 8 }}
- {{- end }}
- spec:
- automountServiceAccountToken: false
- terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
- securityContext:
- runAsNonRoot: true
- runAsUser: 10000
- runAsGroup: 10000
- fsGroup: 10000
- fsGroupChangePolicy: OnRootMismatch
- {{- with .Values.imagePullSecrets }}
- imagePullSecrets:
- {{- toYaml . | nindent 8 }}
- {{- end }}
- containers:
- - name: worker
- image: {{ include "mirum.image" (dict "root" . "image" .Values.worker.image) | quote }}
- imagePullPolicy: {{ .Values.worker.image.pullPolicy }}
- args: ["--config=/etc/mirum/secret/config.yaml"]
- securityContext:
- allowPrivilegeEscalation: false
- capabilities:
- drop: [ALL]
- readOnlyRootFilesystem: true
- {{- with .Values.worker.extraEnv }}
- env:
- {{- toYaml . | nindent 12 }}
- {{- end }}
- resources:
- {{- toYaml .Values.worker.resources | nindent 12 }}
- volumeMounts:
- - name: config
- mountPath: /etc/mirum/secret
- readOnly: true
- - name: workspace
- mountPath: /var/lib/mirum-worker
- - name: tmp
- mountPath: /tmp
- volumes:
- - name: config
- secret:
- secretName: {{ .Values.worker.existingSecret }}
- defaultMode: 0440
- - name: workspace
- emptyDir: {}
- - name: tmp
- emptyDir: {}
- {{- with .Values.worker.nodeSelector }}
- nodeSelector:
- {{- toYaml . | nindent 8 }}
- {{- end }}
- {{- with .Values.worker.affinity }}
- affinity:
- {{- toYaml . | nindent 8 }}
- {{- end }}
- {{- with .Values.worker.tolerations }}
- tolerations:
- {{- toYaml . | nindent 8 }}
- {{- end }}
-{{- end }}
-
-# vim: set filetype=helm:
diff --git a/charts/mirum/values.yaml b/charts/mirum/values.yaml
deleted file mode 100644
--- a/charts/mirum/values.yaml
+++ /dev/null
@@ -1,75 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-imagePullSecrets: []
-nameOverride: ""
-fullnameOverride: ""
-
-server:
- enabled: true
- replicaCount: 1
- image:
- repository: ghcr.io/dimidiumlabs/mirum-server
- tag: ""
- digest: ""
- pullPolicy: IfNotPresent
- # Must contain config.yaml and any private files other than the gRPC
- # certificate. Keep database_uri, pepper, token, and webhook_secret in this
- # Secret rather than Helm values.
- existingSecret: mirum-server
- # Optional existing ServiceAccount used by the server. The default empty
- # value preserves the current Deployment and external database path.
- serviceAccountName: ""
- postgresqlMtls:
- # Opt-in client-certificate mount for passwordless PostgreSQL mTLS. Disabled
- # by default; no CSI resources or volume mounts are rendered unless enabled.
- enabled: false
- mountPath: /etc/mirum/postgresql-tls
- issuerName: ""
- issuerKind: ClusterIssuer
- commonName: ""
- uriSan: "spiffe://ddlabs.internal/ns/${POD_NAMESPACE}/sa/${SERVICE_ACCOUNT_NAME}/pod/${POD_UID}"
- duration: 2160h
- renewBefore: 360h
- fsGroup: 10000
- grpcTls:
- # Optional cert-manager-style Secret containing tls.crt and tls.key. The
- # files are mounted at /etc/mirum/grpc-tls/ for config.yaml to reference.
- existingSecret: ""
- webPort: 3000
- grpcPort: 2000
- route:
- enabled: false
- hostnames: []
- parentRefs: []
- grpcRoute:
- enabled: false
- parentRefs: []
- resources: {}
- extraEnv: []
- podAnnotations: {}
- podLabels: {}
- nodeSelector: {}
- tolerations: []
- affinity: {}
-
-worker:
- enabled: false
- replicaCount: 1
- image:
- repository: ghcr.io/dimidiumlabs/mirum-worker
- tag: ""
- digest: ""
- pullPolicy: IfNotPresent
- # Must contain config.yaml, the Ed25519 key referenced by key_file, and an
- # optional CA file referenced by tls_ca.
- existingSecret: mirum-worker
- resources: {}
- extraEnv: []
- podAnnotations: {}
- podLabels: {}
- nodeSelector: {}
- tolerations: []
- affinity: {}
-
-terminationGracePeriodSeconds: 40
diff --git a/cmd/mirum-server/Dockerfile b/cmd/mirum-server/Dockerfile
deleted file mode 100644
--- a/cmd/mirum-server/Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-FROM gcr.io/distroless/static-debian13:nonroot@sha256:1c2c046bc09ed40fad370b599a0b1ae7987f55b01e247cf27a7c27cd97e5bbc7
-
-ARG TARGETARCH
-
-LABEL org.opencontainers.image.source="https://github.com/dimidiumlabs/mirum" \
- org.opencontainers.image.licenses="AGPL-3.0-or-later" \
- org.opencontainers.image.title="mirum-server"
-
-COPY --chown=root:root --chmod=0755 .container/mirum-server-linux-${TARGETARCH} /usr/local/bin/mirum-server
-COPY LICENSE README.md /usr/share/doc/mirum/
-
-USER 10000:10000
-EXPOSE 3000 2000
-ENTRYPOINT ["/usr/local/bin/mirum-server"]
-CMD ["daemon", "--config=/etc/mirum/config.yaml"]
-
-# syntax=docker/dockerfile:
diff --git a/cmd/mirum-worker/Dockerfile b/cmd/mirum-worker/Dockerfile
deleted file mode 100644
--- a/cmd/mirum-worker/Dockerfile
+++ /dev/null
@@ -1,26 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Nikolay Govorov
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-FROM docker.io/library/alpine:3.23.5@sha256:fd791d74b68913cbb027c6546007b3f0d3bc45125f797758156952bc2d6daf40
-
-ARG TARGETARCH
-
-LABEL org.opencontainers.image.source="https://github.com/dimidiumlabs/mirum" \
- org.opencontainers.image.licenses="AGPL-3.0-or-later" \
- org.opencontainers.image.title="mirum-worker"
-
-RUN apk add --no-cache bash ca-certificates git && \
- addgroup -g 10000 mirum-worker && \
- adduser -D -H -u 10000 -G mirum-worker -h /var/lib/mirum-worker \
- -s /sbin/nologin mirum-worker && \
- install -d -o mirum-worker -g mirum-worker -m 0750 /var/lib/mirum-worker
-
-COPY --chown=root:root --chmod=0755 .container/mirum-worker-linux-${TARGETARCH} /usr/local/bin/mirum-worker
-COPY LICENSE README.md /usr/share/doc/mirum/
-
-USER 10000:10000
-WORKDIR /var/lib/mirum-worker
-ENTRYPOINT ["/usr/local/bin/mirum-worker"]
-CMD ["--config=/etc/mirum/config.yaml"]
-
-# syntax=docker/dockerfile:
diff --git a/mise.lock b/mise.lock
index c1cad8c..ea51012 100644
--- a/mise.lock
+++ b/mise.lock
@@ -56,6 +56,20 @@ url = "https://nodejs.org/dist/v24.18.0/node-v24.18.0-linux-arm64.tar.gz"
checksum = "sha256:783130984963db7ba9cbd01089eaf2c2efb055c7c1693c943174b967b3050cb8"
url = "https://nodejs.org/dist/v24.18.0/node-v24.18.0-linux-x64.tar.gz"
+[[tools.rclone]]
+version = "1.74.4"
+backend = "aqua:rclone/rclone"
+
+[tools.rclone."platforms.linux-arm64"]
+checksum = "sha256:97685285c9ad6a0cf17d5844115d2a67245af6444db672187074bd9c358de419"
+url = "https://github.com/rclone/rclone/releases/download/v1.74.4/rclone-v1.74.4-linux-arm64.zip"
+url_api = "https://api.github.com/repos/rclone/rclone/releases/assets/470550100"
+
+[tools.rclone."platforms.linux-x64"]
+checksum = "sha256:fe435e0c36228e7c2f116a8701f01127bb1f694005fc11d1f27186c8bca4115d"
+url = "https://github.com/rclone/rclone/releases/download/v1.74.4/rclone-v1.74.4-linux-amd64.zip"
+url_api = "https://api.github.com/repos/rclone/rclone/releases/assets/470549540"
+
[[tools.task]]
version = "3.52.0"
backend = "aqua:go-task/task"
diff --git a/mise.toml b/mise.toml
index 9170cef..1be13f0 100644
--- a/mise.toml
+++ b/mise.toml
@@ -11,6 +11,7 @@ buf = "1.67.0"
gh = "2.96.0"
go = "1.26.6"
node = "24.18.0"
+rclone = "1.74.4"
task = "3.52.0" # Removed after Taskfile.yml is migrated to mise tasks.
zig = "0.16.0"
@@ -18,21 +19,18 @@ zig = "0.16.0"
# APT
"apt:apt-utils" = "latest"
"apt:createrepo-c" = "latest"
-"apt:debsigs" = "latest"
"apt:gnupg" = "latest"
"apt:openssl" = "latest"
-"apt:rpm" = "latest"
"apt:zip" = "latest"
# DNF
"dnf:createrepo_c" = "latest"
"dnf:gnupg2" = "latest"
"dnf:openssl" = "latest"
-"dnf:rpm" = "latest"
"dnf:zip" = "latest"
[task_config]
dir = "{{cwd}}"
includes = [
- "git::https://github.com/dimidiumlabs/platform.git//tasks?ref=8bc35fe8be889c50db2d1fb4425cc1b4097dc6b8",
+ "git::https://github.com/dimidiumlabs/infra.git//tasks?ref=9e7330a3e5bde39a87e0ac1b76c9e85db7a6d64a",
]
diff --git a/nfpm.yaml b/nfpm.yaml
index a0fc6ad..e3c23af 100644
--- a/nfpm.yaml
+++ b/nfpm.yaml
@@ -127,6 +127,6 @@ rpm:
apk:
signature:
key_file: ${APK_SIGNING_KEY}
- # nFPM appends ".rsa.pub"; the versioned basename lets clients retain
- # historical package keys during rotation.
- key_name: packages.${PACKAGE_KEY_VERSION}
+ # nfpm appends ".rsa.pub" to this value when embedding the signature;
+ # clients must install the public key as /etc/apk/keys/mirum.rsa.pub.
+ key_name: mirum
diff --git a/packaging/apt-ftparchive.conf b/packaging/apt-ftparchive.conf
new file mode 100644
--- /dev/null
+++ b/packaging/apt-ftparchive.conf
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: 2026 Nikolay Govorov
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+Dir {
+ ArchiveDir ".";
+ CacheDir "/tmp/apt-cache";
+};
+
+Default {
+ Packages::Compress ". gzip";
+ Packages::Extensions ".deb";
+};
+
+TreeDefault {
+ Packages "$(DIST)/$(SECTION)/binary-$(ARCH)/Packages";
+ BinCacheDB "packages-$(DIST)-$(ARCH).db";
+};
+
+Tree "dists/stable" {
+ Sections "main";
+ Architectures "amd64 arm64 riscv64 ppc64le";
+ Directory "pool/stable";
+};
+
+Tree "dists/nightly" {
+ Sections "main";
+ Architectures "amd64 arm64 riscv64 ppc64le";
+ Directory "pool/nightly";
+};