Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23d3a00ae1 | ||
|
|
4379a17b15 | ||
|
|
983e05a816 | ||
|
|
dd6a64d953 |
No files matched your search
@@ -31,6 +31,28 @@ den Einstellungen.
|
||||
Nächste Codenamen (der Reihe nach, wenn die jeweils nächste MINOR-Version
|
||||
ansteht): Merlin …
|
||||
|
||||
## [1.23.10] "Harrier" — 2026-10-20
|
||||
|
||||
- **Signierte Release-Images:** Die Images (backend, frontend, proxy, updater) werden mit cosign signiert, beginnend mit 1.23.9. Der öffentliche
|
||||
Schlüssel liegt als `cosign.pub` im Repository und im Release-Bundle. `opnexus update` prüft die Signaturen vor dem Wechsel, wenn `cosign`
|
||||
installiert ist. Anleitung: Handbuch, „Images prüfen“.
|
||||
|
||||
## [1.23.9] "Harrier" — 2026-10-20
|
||||
|
||||
- Update-Karte: Der Hinweis für Installationen ohne Release-Images nennt jetzt die tatsächliche Ursache („OPNEXUS_IMAGE_REPO ist nicht gesetzt“)
|
||||
statt „baut aus dem Quellcode“.
|
||||
- `cosign.pub`: öffentlicher Schlüssel für die Signaturen der Release-Images (das Release-Skript kann Images jetzt signieren).
|
||||
|
||||
## [1.23.8] "Harrier" — 2026-10-20
|
||||
|
||||
- **Einstellungen › OPNexus aktualisieren:** Auf einer Installation, die aus dem Quellcode gebaut wird (kein `OPNEXUS_IMAGE_REPO`), erscheint nicht mehr
|
||||
die Anleitung zum Aktivieren des Updaters – Updates per Klick gibt es dort ohnehin nicht –, sondern nur der Hinweis auf `git pull` und
|
||||
`docker compose up -d --build`. Das Backend erkennt den Modus jetzt selbst (neue Umgebungsvariable im Compose-File).
|
||||
|
||||
## [1.23.7] "Harrier" — 2026-10-20
|
||||
|
||||
- Hinweistext der Versionsprüfung verweist auf den Schalter „oben“ statt „unten“.
|
||||
|
||||
## [1.23.6] "Harrier" — 2026-10-20
|
||||
|
||||
- **Versionsprüfung im Webinterface:** Unter Einstellungen › OPNexus aktualisieren lässt sich die Prüfung auf neue Versionen jetzt per Schalter
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ Zentrale Verwaltung mehrerer [OPNsense](https://opnsense.org)-Firewalls: Regeln,
|
||||
|
||||

|
||||
|
||||
> **Stand:** `1.23.6` ist die aktuelle stabile Version. Entwickelt und getestet wurde gegen echte OPNsense-Instanzen; eine frische Installation aus dem Release-Bundle sowie Updates und Rollbacks sind durchgängig geprüft. Ecken und Kanten bitte melden.
|
||||
> **Stand:** `1.23.10` ist die aktuelle stabile Version. Entwickelt und getestet wurde gegen echte OPNsense-Instanzen; eine frische Installation aus dem Release-Bundle sowie Updates und Rollbacks sind durchgängig geprüft. Ecken und Kanten bitte melden.
|
||||
|
||||
## Funktionen
|
||||
|
||||
@@ -62,7 +62,7 @@ Für den Zugriff von anderen Rechnern und den Produktivbetrieb mit TLS (mitgelie
|
||||
|
||||
```bash
|
||||
OPNEXUS_IMAGE_REPO=git.opnexus.dev/opnexus
|
||||
OPNEXUS_VERSION=1.23.6
|
||||
OPNEXUS_VERSION=1.23.10
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
@@ -7,7 +7,7 @@ Central management for multiple [OPNsense](https://opnsense.org) firewalls: rule
|
||||
|
||||

|
||||
|
||||
> **Status:** `1.23.6` is the current stable release. It has been developed and tested against real OPNsense instances; a clean install from the release bundle, updates and rollbacks have been verified end to end. Please report rough edges.
|
||||
> **Status:** `1.23.10` is the current stable release. It has been developed and tested against real OPNsense instances; a clean install from the release bundle, updates and rollbacks have been verified end to end. Please report rough edges.
|
||||
|
||||
## What it does
|
||||
|
||||
@@ -64,7 +64,7 @@ For access from other machines and for production use with TLS (bundled Caddy pr
|
||||
|
||||
```bash
|
||||
OPNEXUS_IMAGE_REPO=git.opnexus.dev/opnexus
|
||||
OPNEXUS_VERSION=1.23.6
|
||||
OPNEXUS_VERSION=1.23.10
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
@@ -27,6 +27,9 @@ class Settings(BaseSettings):
|
||||
# keine Instanz- oder Nutzerdaten.
|
||||
update_check_url: str = ""
|
||||
update_check_interval_hours: int = 12
|
||||
# Registry der Release-Images (OPNEXUS_IMAGE_REPO). Leer = OPNexus wird lokal aus dem
|
||||
# Quellcode gebaut; dann gibt es keine Updates per Klick (nur der Hinweis in den Einstellungen).
|
||||
opnexus_image_repo: str = ""
|
||||
|
||||
# ── Updates aus dem Webinterface (app/services/updater_client.py) ─────
|
||||
# Optionaler Updater-Container (Compose-Profil "updater"). Das Backend hat
|
||||
|
||||
@@ -104,6 +104,9 @@ async def updater_status(db: AsyncSession = Depends(get_db), user: AdminUser = D
|
||||
updater = await updater_client.status()
|
||||
except updater_client.UpdaterUnavailable as exc:
|
||||
result["reason"] = str(exc)
|
||||
# Without the updater the install mode is still known from the image registry setting; the UI uses it
|
||||
# to not offer enabling the updater on an install that builds from source (it could not update anyway).
|
||||
result["mode"] = "release" if settings.opnexus_image_repo.strip() else "local"
|
||||
return result
|
||||
except updater_client.UpdaterRejected:
|
||||
result["reason"] = "unreachable"
|
||||
|
||||
@@ -6,5 +6,5 @@ convention — but both are bumped together whenever a release ships).
|
||||
Versioning scheme: see CHANGELOG.md ("Versionierung").
|
||||
"""
|
||||
|
||||
APP_VERSION = "1.23.6"
|
||||
APP_VERSION = "1.23.10"
|
||||
APP_CODENAME = "Harrier"
|
||||
@@ -58,6 +58,17 @@ async def test_status_without_token_is_unavailable_not_an_error(client, respx_mo
|
||||
assert body["update_available"] is True # der Hinweis bleibt trotzdem
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("repo,mode", [("", "local"), ("git.example.test/opnexus", "release")])
|
||||
async def test_install_mode_is_known_without_the_updater(client, respx_mock, monkeypatch, tmp_path, repo, mode):
|
||||
# The panel must not tell a source-built install to enable an updater that could not update it anyway.
|
||||
monkeypatch.setattr(settings, "updater_token_file", str(tmp_path / "missing"))
|
||||
monkeypatch.setattr(settings, "opnexus_image_repo", repo)
|
||||
_feed(respx_mock, _bump(minor=1))
|
||||
body = (await client.get("/api/system/updater")).json()
|
||||
assert body["available"] is False and body["reason"] == "not_enabled" and body["mode"] == mode
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_status_unreachable_updater(client, respx_mock):
|
||||
_feed(respx_mock, _bump(minor=1))
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEA4pZWkNMkAtCGc54M2wuWy7CXwkT
|
||||
3PCysv1/1IbkyJRPdM8+DFf26fBxWG9P9PLKfwavhqVYtHILxxzxKmtjeQ==
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -116,6 +116,7 @@ services:
|
||||
COOKIE_SECURE: ${COOKIE_SECURE:-false}
|
||||
TRUST_PROXY_HEADERS: ${TRUST_PROXY_HEADERS:-false}
|
||||
UPDATE_CHECK_URL: ${UPDATE_CHECK_URL:-}
|
||||
OPNEXUS_IMAGE_REPO: ${OPNEXUS_IMAGE_REPO:-}
|
||||
ALLOW_INSECURE_FIREWALL_URLS: ${ALLOW_INSECURE_FIREWALL_URLS:-false}
|
||||
ALLOW_INSECURE_SMTP_AUTH: ${ALLOW_INSECURE_SMTP_AUTH:-false}
|
||||
SMTP_CA_FILE: ${SMTP_CA_FILE:-}
|
||||
|
||||
@@ -74,6 +74,31 @@ Alternativ lassen sich auch aus einem Checkout die fertigen Images verwenden: in
|
||||
der `.env` `OPNEXUS_IMAGE_REPO=git.opnexus.dev/opnexus` und `OPNEXUS_VERSION=<version>`
|
||||
setzen, dann `docker compose pull && docker compose up -d --no-build`.
|
||||
|
||||
### Images prüfen (Signatur)
|
||||
|
||||
Die Release-Images sind mit [cosign](https://github.com/sigstore/cosign) signiert (ab 1.23.9).
|
||||
Damit lässt sich prüfen, dass ein Image wirklich von OPNexus stammt und seit dem Bau nicht
|
||||
verändert wurde. Der öffentliche Schlüssel liegt als `cosign.pub` im Repository und im
|
||||
Release-Bundle:
|
||||
|
||||
```bash
|
||||
cosign verify --key cosign.pub --insecure-ignore-tlog=true \
|
||||
git.opnexus.dev/opnexus/opnexus-backend:<version>
|
||||
```
|
||||
|
||||
Das Gleiche gilt für `opnexus-frontend`, `opnexus-proxy` und `opnexus-updater`. Eine
|
||||
erfolgreiche Prüfung gibt die Signatur als JSON aus; bei einem fremden oder fehlenden
|
||||
Schlüssel endet der Befehl mit einem Fehler. `--insecure-ignore-tlog=true` ist hier gewollt:
|
||||
OPNexus lädt Signaturen nicht in das öffentliche Transparenzlog, damit die Prüfung auch in
|
||||
abgeschotteten Netzen funktioniert. Die Signatur gilt dem Inhalt (Digest) des Images, nicht
|
||||
dem Tag.
|
||||
|
||||
`opnexus update` prüft die Signaturen selbst, bevor es etwas wechselt, sobald `cosign`
|
||||
installiert ist und `cosign.pub` neben der `docker-compose.yml` liegt (`cosign.pub` liegt im Bundle
|
||||
bereits dabei, `cosign` selbst musst du installieren). Schlägt die Prüfung fehl, bricht das
|
||||
Update ab und es wurde nichts verändert. Fehlt `cosign`, sagt `opnexus update` das und
|
||||
macht ohne Prüfung weiter.
|
||||
|
||||
### Erster Start und Passwort
|
||||
|
||||
Ohne `ADMIN_PASSWORD` in der `.env` erzeugt OPNexus beim ersten Start ein
|
||||
|
||||
@@ -208,7 +208,9 @@ export function OpnexusUpdateSection() {
|
||||
|
||||
{!status.available && (
|
||||
<div className="space-y-2 rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-700">
|
||||
{status.reason === "not_enabled" || status.reason === "unauthorized" ? (
|
||||
{(status.reason === "not_enabled" || status.reason === "unauthorized") && status.mode === "local" ? (
|
||||
<p>{t("settings.update.localMode")}</p>
|
||||
) : status.reason === "not_enabled" || status.reason === "unauthorized" ? (
|
||||
<>
|
||||
<p className="font-medium">{t("settings.update.notEnabledTitle")}</p>
|
||||
<p>{t("settings.update.notEnabledBody")}</p>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
"upToDate": "OPNexus ist auf dem neuesten Stand.",
|
||||
"notes": "Release-Notes",
|
||||
"checked": "Zuletzt geprüft: {time}",
|
||||
"feedOff": "Die Versionsprüfung ist aus. Unten einschalten, damit OPNexus neue Versionen erkennt.",
|
||||
"feedOff": "Die Versionsprüfung ist aus. Schalte sie oben ein, damit OPNexus neue Versionen erkennt.",
|
||||
"feedTitle": "Auf neue Versionen prüfen",
|
||||
"feedHint": "Fragt regelmäßig den Release-Feed ab, ob eine neuere Version erschienen ist. Gesendet wird nur eine einfache Anfrage (GET) mit der eigenen Versionsnummer, nichts sonst. Standardmäßig aus.",
|
||||
"feedToggle": "Versionsprüfung aktivieren",
|
||||
@@ -138,7 +138,7 @@
|
||||
"notEnabledImages": "Das geht nur mit Release-Images (Release-Bundle oder OPNEXUS_IMAGE_REPO in der .env). Wer OPNexus selbst aus dem Quellcode baut, aktualisiert mit „git pull“ und „docker compose up -d --build“.",
|
||||
"notEnabledCli": "Bis dahin geht das Update auf dem Server mit „opnexus update“.",
|
||||
"unreachable": "Der Updater antwortet nicht. Auf dem Server prüfen: docker compose ps updater",
|
||||
"localMode": "Diese Installation baut OPNexus lokal aus dem Quellcode (kein Release-Image). Aktualisieren auf dem Server mit git pull und docker compose up -d --build.",
|
||||
"localMode": "Diese Installation nutzt keine Release-Images (OPNEXUS_IMAGE_REPO ist in der .env nicht gesetzt). Aktualisieren auf dem Server mit „git pull“ und „docker compose up -d --build“.",
|
||||
"majorChange": "Version {latest} ist ein Hauptversions-Sprung. Bitte erst die Release-Notes lesen und dann auf dem Server mit „opnexus update {latest}“ aktualisieren.",
|
||||
"button": "Auf {latest} aktualisieren",
|
||||
"confirmTitle": "Auf {latest} aktualisieren?",
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
"upToDate": "OPNexus is up to date.",
|
||||
"notes": "Release notes",
|
||||
"checked": "Last checked: {time}",
|
||||
"feedOff": "The version check is off. Switch it on below so OPNexus can detect new versions.",
|
||||
"feedOff": "The version check is off. Switch it on above so OPNexus can detect new versions.",
|
||||
"feedTitle": "Check for new versions",
|
||||
"feedHint": "Regularly asks the release feed whether a newer version has been published. Only a plain request (GET) carrying your own version number is sent, nothing else. Off by default.",
|
||||
"feedToggle": "Enable version check",
|
||||
@@ -138,7 +138,7 @@
|
||||
"notEnabledImages": "This only works with release images (release bundle, or OPNEXUS_IMAGE_REPO in the .env). If you build OPNexus from source, update with “git pull” and “docker compose up -d --build”.",
|
||||
"notEnabledCli": "Until then, update on the server with “opnexus update”.",
|
||||
"unreachable": "The updater does not respond. Check on the server: docker compose ps updater",
|
||||
"localMode": "This installation builds OPNexus locally from source (no release image). Update on the server with git pull and docker compose up -d --build.",
|
||||
"localMode": "This installation does not use release images (OPNEXUS_IMAGE_REPO is not set in the .env). Update on the server with “git pull” and “docker compose up -d --build”.",
|
||||
"majorChange": "Version {latest} is a major version jump. Please read the release notes first, then update on the server with “opnexus update {latest}”.",
|
||||
"button": "Update to {latest}",
|
||||
"confirmTitle": "Update to {latest}?",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Manually bumped whenever a notable change ships — mirrors the dated
|
||||
// entries already kept in the project README/CHANGELOG.md, no build
|
||||
// tooling involved. Versioning scheme: see CHANGELOG.md ("Versionierung").
|
||||
export const APP_VERSION = "1.23.6";
|
||||
export const APP_VERSION = "1.23.10";
|
||||
export const APP_CODENAME = "Harrier";
|
||||
export const APP_MAINTAINER = "Julian Boldt";
|
||||
@@ -9,6 +9,8 @@
|
||||
# scripts/build_release_images.sh v1.10.0 --push # bauen und pushen
|
||||
# scripts/build_release_images.sh v1.10.0 --push --multiarch # amd64+arm64 (braucht QEMU/buildx)
|
||||
#
|
||||
# Signieren (cosign): OPNEXUS_SIGN=1 COSIGN_KEY=/pfad/cosign.key [COSIGN_PASSWORD=…] — der öffentliche
|
||||
# Schlüssel liegt als cosign.pub im Repo; die Registry muss ihren Token-Realm per https melden.
|
||||
# REPO: Umgebungsvariable OPNEXUS_IMAGE_REPO (Standard git.opnexus.dev/opnexus).
|
||||
# Hinweis: Hinter dem Cloudflare-Proxy (Free) scheitern Pushes mit Layern > 100 MB —
|
||||
# dann die Registry-Domain auf "DNS only" stellen oder aus dem LAN pushen.
|
||||
@@ -45,5 +47,19 @@ for svc in backend frontend proxy updater; do
|
||||
docker build "${targs[@]}" "$src/$svc"
|
||||
if [ "$push" = 1 ]; then for t in "${tags[@]}"; do docker push "$image:$t"; done; fi
|
||||
fi
|
||||
if [ "$push" = 1 ] && [ "${OPNEXUS_SIGN:-0}" = 1 ]; then
|
||||
# Signiert wird der Digest (nicht der veränderliche Tag). Ein Schlüssel: COSIGN_KEY (+ COSIGN_PASSWORD).
|
||||
[ -n "${COSIGN_KEY:-}" ] || { echo "OPNEXUS_SIGN=1, aber COSIGN_KEY ist nicht gesetzt" >&2; exit 1; }
|
||||
if [ "$multi" = 1 ]; then
|
||||
digest="$(docker buildx imagetools inspect "$image:$version" --format '{{json .Manifest.Digest}}' | tr -d '"')"
|
||||
else
|
||||
digest="$(docker image inspect "$image:$version" --format '{{json .RepoDigests}}' | tr ',' '\n' | grep -F "$image@" | tr -d '[]"')"; digest="${digest##*@}"
|
||||
fi
|
||||
[ -n "$digest" ] || { echo "Digest von $image:$version nicht gefunden (Push fehlgeschlagen?)" >&2; exit 1; }
|
||||
# Ohne öffentliches Transparenzlog (Rekor): Prüfen soll auch in abgeschotteten Netzen gehen.
|
||||
cosign sign --yes --use-signing-config=false --tlog-upload=false --key "$COSIGN_KEY" "$image@$digest"
|
||||
cosign verify --key cosign.pub --insecure-ignore-tlog=true "$image@$digest" >/dev/null
|
||||
echo " signiert: $image@$digest"
|
||||
fi
|
||||
done
|
||||
[ "$push" = 1 ] && echo "Fertig und gepusht: $repo (${tags[*]})" || echo "Fertig (lokal gebaut, nicht gepusht)."
|
||||
@@ -33,6 +33,7 @@ sed -e "s|^# OPNEXUS_IMAGE_REPO=.*|OPNEXUS_IMAGE_REPO=$repo|" \
|
||||
|
||||
cp scripts/opnexus "$out/opnexus"
|
||||
cp LICENSE "$out/"
|
||||
cp cosign.pub "$out/"
|
||||
cat > "$out/INSTALL.txt" <<TXT
|
||||
OPNexus $version
|
||||
|
||||
|
||||
@@ -217,6 +217,23 @@ cmd_restore() {
|
||||
say "Wiederhergestellt."
|
||||
}
|
||||
|
||||
# Prüft die Signatur der gezogenen Images (cosign), bevor irgendetwas gewechselt wird. Nur wenn `cosign`
|
||||
# installiert ist und cosign.pub neben der docker-compose.yml liegt; sonst wird das gesagt und übersprungen.
|
||||
verify_signatures() {
|
||||
local target="$1"; shift
|
||||
local repo; repo=$(env_get OPNEXUS_IMAGE_REPO)
|
||||
if ! command -v cosign >/dev/null 2>&1 || [ ! -f cosign.pub ]; then
|
||||
say "Signaturprüfung übersprungen (cosign oder cosign.pub fehlt — siehe Handbuch, „Images prüfen“)."
|
||||
return 0
|
||||
fi
|
||||
local svc
|
||||
for svc in "$@"; do
|
||||
cosign verify --key cosign.pub --insecure-ignore-tlog=true "$repo/opnexus-$svc:$target" >/dev/null 2>&1 \
|
||||
|| die "Signatur von $repo/opnexus-$svc:$target ist ungültig oder fehlt — nichts wurde verändert."
|
||||
done
|
||||
say "Signaturen geprüft."
|
||||
}
|
||||
|
||||
cmd_update() {
|
||||
require_release_mode
|
||||
local target="${1:-$(env_get OPNEXUS_VERSION)}"
|
||||
@@ -235,6 +252,7 @@ cmd_update() {
|
||||
local pull_services=("${SERVICES[@]}")
|
||||
if updater_enabled; then pull_services+=(updater); fi
|
||||
OPNEXUS_VERSION="$target" c pull "${pull_services[@]}" || die "Pull fehlgeschlagen — nichts wurde verändert."
|
||||
verify_signatures "$target" "${pull_services[@]}"
|
||||
|
||||
started=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
cat > "$STATE_FILE" <<STATE
|
||||
|
||||
Reference in new issue
Block a user