From 6d5671f75b2bb3b982bd930e1be4e17c03cc491e Mon Sep 17 00:00:00 2001 From: Mikei386 <44135113+Mikei386@users.noreply.github.com> Date: Mon, 28 Sep 2026 15:42:53 +0200 Subject: [PATCH] Move development runtime to isolated Athena Debian instance --- ACCESS.md | 23 ++++++++--------------- DEVELOPMENT.md | 43 ++++++++++++++++++++++++++++++++++++++++++ INSTALL.md | 3 ++- README.md | 46 ++++++++++++++++----------------------------- collect_hardware.py | 2 +- deploy/Dockerfile | 2 +- deploy/install.py | 11 ++++++++--- deploy/smoke.py | 2 +- network-ui.js | 4 ++-- network/README.md | 16 +++++++++------- server.py | 6 +++--- test_server.py | 2 +- 12 files changed, 95 insertions(+), 65 deletions(-) create mode 100644 DEVELOPMENT.md diff --git a/ACCESS.md b/ACCESS.md index 0b125fa..138f9f2 100644 --- a/ACCESS.md +++ b/ACCESS.md @@ -2,7 +2,7 @@ ## Ersteinrichtung -Beim ersten Öffnen der lokalen Oberfläche legt der Betreiber zwei getrennte +Bei der ersten Einrichtung legt der Betreiber zwei getrennte Zugangsdaten fest: 1. **Oberflächenkennwort**: 16–256 Zeichen, ein Administratorzugang. @@ -17,19 +17,12 @@ Auf HTTP-Adressen kann die Browser-Zwischenablage gesperrt sein. Dann „Token a verwenden und manuell kopieren. Im ersten Schritt wird noch keine Sitzung erzeugt: nach dem Einrichten mit dem gewählten Kennwort anmelden. -Lokaler Zustand: `.state/auth.json`, Verzeichnis 0700, Datei 0600, in Git und -Docker-Builds ausgeschlossen. Es gibt keine voreingestellten oder vom Agenten -festgelegten Zugangsdaten. Auch die Mac-Verwaltungsoberfläche verlangt jetzt die -Ersteinrichtung und Anmeldung. Status, Hardware und Steuerung sind davor gesperrt. -Der Ersteinrichtungs-Endpunkt ist einmalig und nur in der Loopback-Instanz aktiv. - -Die optionale Athena-Serverinstallation erhält in ihrem Installationsformular -**eigene** Zugangsdaten (Kennwort und API-Token). Diese gelten für die Server-Instanz, -nicht für die Mac-Instanz. Die Server-Anwendung wird bereits provisioniert gestartet; -es gibt keinen ungeschützten Fernzugriff, mit dem ein beliebiger Besucher den -Server beanspruchen könnte. Ein vorhandener 0.2-Kennwortstand bleibt lesbar; -API-Zugriff ist dort zunächst deaktiviert, bis ein Token eingerichtet wird. -Bestehende Server-Container werden durch diese Codeänderung nicht automatisch aktualisiert. +Der Debian-Installer richtet die Zugangsdaten vor dem Start ein. Speicherung unter +`state/auth.json` im privaten Installationsverzeichnis, Datei 0600. Es gibt keine +voreingestellten Zugangsdaten. Status, Hardware und Steuerung sind anmeldepflichtig. +Der Ersteinrichtungs-Endpunkt ist im provisionierten Serverbetrieb deaktiviert. +Die isolierte Entwicklungsinstanz erlaubt eine neue einmalige Einrichtung über +den SSH-Tunnel. Zugangsdaten der früheren Vorschau werden nicht übertragen. ## Einstellungen → Zugang & API @@ -41,7 +34,7 @@ Bestehende Server-Container werden durch diese Codeänderung nicht automatisch a Browser-Sitzungen bleiben gültig. API-Clients müssen den neuen Token erhalten. - **Abmelden:** beendet die aktuelle Sitzung serverseitig. -Die Einstellungsseite benennt die gerade verwaltete Instanz (Mac oder Athena). +Die Einstellungsseite benennt die gerade verwaltete Instanz auf dem Debian-Server. Es gibt zunächst **einen Administrator**, keine Benutzernamen, weiteren Benutzer, Rollen, persönlichen Tokens oder Passwort-zurücksetzen-per-E-Mail. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..46b05a7 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,43 @@ +# Entwicklung auf Athena (Debian) + +Zielsystem: Debian 13, RTX 5080 und RTX 3060. Der Arbeitsplatz dient nur als +Editor/SSH-Client und Browser. Die Anwendung und ihre Tests laufen auf Athena. + +- Quellcode: `/opt/athena-deck-dev/source` +- Eigener Container: `athena-deck-dev` +- Zustand und Installationsmanifest: `/opt/athena-deck-dev/runtime` +- Serverbindung: ausschließlich `127.0.0.1:8108` +- GPU-Zugriff: NVIDIA `utility` für Telemetrie; keine Modellstarts. + +Vom Arbeitsplatz: + +```sh +ssh -i /Users/mike_i386/.ssh/athena_key -o BatchMode=yes -N -o ExitOnForwardFailure=yes -L 8108:127.0.0.1:8108 root@192.168.1.212 +``` + +Browser: http://127.0.0.1:8108 . Die Adresse führt durch den Tunnel zum Server. +Beim ersten Öffnen neue Zugangsdaten einrichten. Vorhandene Zugangsdaten werden +nicht vom Arbeitsplatz übertragen. Browser-Profilentwürfe bleiben bei gleicher +Adresse erhalten. Nur diese isolierte Entwicklungsinstanz erlaubt die einmalige +Browser-Einrichtung über den SSH-Tunnel (`development_setup` im Manifest). +Der normale Debian-Installer provisioniert weiterhin vor dem Start. + +Auf Athena: + +```sh +cd /opt/athena-deck-dev/source +./install.sh --status --directory /opt/athena-deck-dev/runtime +./install.sh --stop --directory /opt/athena-deck-dev/runtime +./install.sh --start --directory /opt/athena-deck-dev/runtime +# Nach gezielter Aktualisierung der Quelldateien: +./install.sh --update --directory /opt/athena-deck-dev/runtime +python3 -m unittest discover -s . -v +``` + +Diese Befehle verwalten ausschließlich den eigenen, per Label geprüften +Deck-Container. Produktiver Router, Modelle, WireGuard und Hostkonfiguration +werden nicht verändert. Kein Docker-Socket im Webcontainer. + +Modellkatalog, Downloads, Profile und llama.cpp-Build/Update sind weiterhin +GUI-Entwürfe. Die Netzwerk-Erweiterung ist in dieser Installation deaktiviert. +Das Verschieben der Entwicklung aktiviert keine dieser Funktionen automatisch. diff --git a/INSTALL.md b/INSTALL.md index 1bd453b..93364e9 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -89,7 +89,8 @@ Danach [Athena Deck](http://127.0.0.1:8110) öffnen und mit dem bei der Installa gewählten Kennwort anmelden. Terminal offen halten; Ctrl+C beendet nur den Tunnel. Bei anderem Installationsport beide Portangaben entsprechend anpassen. Der lokale Browserport sollte dem gewählten Serverport entsprechen (Host-Allowlist). -Die bestehende Mac-Vorschau auf Port 8108 bleibt eine separate Instanz. +Der Arbeitsplatz führt nur den Browser und SSH-Tunnel aus. Auch die Entwicklung +läuft auf Athena; siehe [DEVELOPMENT.md](DEVELOPMENT.md). ## Betrieb und Updates diff --git a/README.md b/README.md index efebb36..cfeafa4 100644 --- a/README.md +++ b/README.md @@ -18,37 +18,24 @@ Downloads und Builds sind deaktiviert. Details: [GUI-Prototyp](STUDIO.md). ## Zugang und API-Token Beim ersten Öffnen werden Oberflächenkennwort und separater API-Token eingerichtet. -Beide sind unter **Zugang & API** änderbar. Die lokale Vorschau ist jetzt ebenfalls -anmeldepflichtig. Details und API-Rechte: [Zugangsverwaltung](ACCESS.md). +Beide sind unter **Zugang & API** änderbar. Der Debian-Installer richtet den Zugang vor dem Serverstart ein. Details und API-Rechte: [Zugangsverwaltung](ACCESS.md). ## WireGuard-Einstellungen -Installation einer getrennten Server-Instanz, sicherer Conf-Import und LAN-/Tunnel-Zugriff -sind jetzt unter Einstellungen verfügbar. Einrichtung, Sicherheitsgrenzen und Tests: -[WireGuard-Modul](network/README.md). Ohne Installation bleibt die Mac-Vorschau -rein lokal; erst der Installationsknopf erstellt den neuen Container auf Athena. +Das separate [WireGuard-Modul](network/README.md) enthält Conf-Import und +LAN-/Tunnel-Zugriff. In der aktuellen Debian-Entwicklungsinstanz ist es nicht +angebunden; der Zugriff erfolgt über SSH-Tunnel. Der bestehende Gateway bleibt unverändert. -## Start und Stopp auf dem Mac +## Zielsystem und Entwicklung -```sh -cd /Users/mike_i386/Documents/ChatGPT/Athena/AI-Profile-Router/experiments/athena-control-ui -python3 server.py --port 8108 -``` +Athena Deck läuft vollständig auf einem Debian-Server mit RTX 5080 und RTX 3060. +Oberfläche, API, Demo-Prozess und Hardware-Erfassung laufen dort. Der Arbeitsplatz +benötigt nur Browser und SSH; er ist kein Anwendungsserver. Auch Builds und +Integrationstests werden auf Athena ausgeführt. Modelllaufzeiten sind noch nicht angebunden. -GUI: http://127.0.0.1:8108 · Beenden mit Ctrl+C im Startterminal. -SIGTERM beendet ebenfalls den Server und seinen Demo-Kindprozess sauber. -Ein belegter UI-Port führt zum Abbruch, nicht zur Übernahme eines Dienstes. -Der Demo-Port wird vom Betriebssystem vergeben und als bereits gebundener -Socket an den Kindprozess weitergereicht (keine Port-Prüfungs-Race). -Kein SSH-Tunnel erforderlich. Die Anwendung bindet ausschließlich Loopback. -Im separaten Git-Repository liegen diese Dateien im Wurzelverzeichnis; -dort entsprechend `cd` in den Checkout und denselben Startbefehl verwenden. - -Hardware-Abfragen verwenden den vorhandenen SSH-Zugang: -`ssh -i ~/.ssh/athena_key -o BatchMode=yes root@192.168.1.212`. -Der bekannte Hostschlüssel muss bereits hinterlegt sein. Schlüssel werden -weder kopiert noch ausgegeben. Athena erhält nur den Collector über stdin; -auf dem Host werden keine Dateien angelegt und keine Dienste gesteuert. +Die isolierte Entwicklungsinstallation ist in [DEVELOPMENT.md](DEVELOPMENT.md) +beschrieben. Hardware wird direkt über `/proc`, hwmon und nvidia-smi gelesen; +Deck benötigt dafür keinen SSH-Schlüssel. Der Demo-Prozess lädt kein Modell. ## Interne API v1 @@ -75,8 +62,8 @@ curl -X POST -H 'Authorization: Bearer ' http://127.0.0.1:8108/api/v1 curl -X POST -H 'Authorization: Bearer ' http://127.0.0.1:8108/api/v1/demo/stop ``` -Hardware: `available` bezeichnet Erfolg der SSH-Collector-Abfrage, einzelne -Messwerte können trotzdem fehlen (`null`). SSH-Ausfall liefert available=false, +Hardware: `available` bezeichnet Erfolg der Hardware-Abfrage, einzelne +Messwerte können trotzdem fehlen (`null`). Ein Ausfall der Erfassung liefert available=false, leere Daten und eine Fehlermeldung, keine alten Werte als vermeintliches Livebild. CPU-Auslastung: 250-ms-Differenz aus `/proc/stat` ohne doppelte Guest-Zählung. RAM: MemTotal minus MemAvailable aus `/proc/meminfo`, Einheit Bytes. @@ -90,7 +77,7 @@ Keine Historie und kein Hintergrund-Collector bei geschlossener Hardware-Seite. ## Struktur und Grenzen - `server.py`: API, separater HardwareProvider, eigenständiger DemoService. -- `demo.py`: Health-only HTTP-Kindprozess auf dem Mac, ohne Modellabhängigkeiten. +- `demo.py`: Health-only HTTP-Kindprozess auf dem Debian-Server, ohne Modellabhängigkeiten. - `collect_hardware.py`: fest begrenzte lesende Linux-Hardware-Abfragen. - `index.html`, `app.js`, `style.css`: neue responsive Oberfläche. - `test_server.py`: Prozess-Lebenszyklus, Kontrollgrenzen, Hardware-Ausfall. @@ -102,8 +89,7 @@ mit derselben Status-/Start-/Stopp-Trennung erhalten. Noch kein Worker-Registry, Scheduler oder produktionsreifer Worker-Supervisor. Die optionale Server-Instanz hat eine eigene Passwortanmeldung; ihre Netzwerkgrenzen stehen in der Modul-Dokumentation. SIGKILL/Absturz-Cleanup ist nicht implementiert; regulär Ctrl+C/SIGTERM verwenden. -SSH verwendet den vorgegebenen Root-Zugang; ein eingeschränktes Telemetrie-Konto -wäre ein späterer eigener Auftrag. Der Hardware-Collector ändert keine Host-Konfiguration. Die optionale +Der Hardware-Collector ändert keine Host-Konfiguration. Die optionale Netzwerkmodul-Installation erzeugt einen eigenen Docker-Container samt Portbindungen. ## Verifikation am 28.09.2026 diff --git a/collect_hardware.py b/collect_hardware.py index 5a373c1..d7f503d 100644 --- a/collect_hardware.py +++ b/collect_hardware.py @@ -59,7 +59,7 @@ def collect(): gpus.append(dict(index=int(index), name=name, uuid=uuid, total_mib=number(total), used_mib=number(used), percent=number(usage), temperature_c=number(temp))) except (OSError, subprocess.SubprocessError, ValueError): errors.append('GPU-Messwerte nicht verfügbar') - return dict(source='Athena · SSH /proc + hwmon + nvidia-smi', sampled_at=time.time(), cpu=cpu, ram=ram, gpus=gpus, errors=errors) + return dict(source='Debian-Server · /proc + hwmon + nvidia-smi', sampled_at=time.time(), cpu=cpu, ram=ram, gpus=gpus, errors=errors) if __name__ == '__main__': diff --git a/deploy/Dockerfile b/deploy/Dockerfile index d771010..e08dfbc 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -5,7 +5,7 @@ COPY index.html app.js studio.js style.css login.html login.js access-ui.js netw COPY network/__init__.py network/client.py network/config.py network/rpc.py /app/network/ ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 HOME=/tmp \ DECK_BIND_HOST=0.0.0.0 DECK_STATE_DIR=/var/lib/deck \ - DECK_REQUIRE_SETUP=1 DECK_LOCAL_HARDWARE=1 DECK_LOCATION=Server \ + DECK_REQUIRE_SETUP=1 DECK_LOCAL_HARDWARE=1 DECK_LOCATION=Athena-Debian \ DECK_NETWORK_MODE=disabled USER 65534:65534 CMD ["python3", "server.py", "--port", "8108"] diff --git a/deploy/install.py b/deploy/install.py index e2cea93..73e7551 100644 --- a/deploy/install.py +++ b/deploy/install.py @@ -98,6 +98,10 @@ def launch(config): '-p','127.0.0.1:'+str(config['port'])+':8108', '--health-cmd', 'python3 -c "import urllib.request,json; assert json.load(urllib.request.urlopen(\'http://127.0.0.1:8108/api/v1/auth/status\',timeout=3))[\'initialized\']"', '--health-interval','30s','--health-timeout','5s','--health-retries','3'] + if config.get('development_setup'): + args[args.index('--health-cmd')+1] = 'python3 -c "import urllib.request; urllib.request.urlopen(\'http://127.0.0.1:8108/api/v1/auth/status\',timeout=3)"' + # Explicit isolated development bootstrap, reachable only through host loopback/SSH. + args += ['-e','DECK_REQUIRE_SETUP=0'] if config['gpu_telemetry']: args += ['--gpus','all','-e','NVIDIA_DRIVER_CAPABILITIES=utility'] args.append(config['image']) @@ -111,7 +115,7 @@ def ready(config): if item and item['State']['Running']: try: with urllib.request.urlopen('http://127.0.0.1:'+str(config['port'])+'/api/v1/auth/status',timeout=2) as r: - if json.load(r).get('initialized') is True: + if json.load(r).get('initialized') is True or config.get('development_setup'): return except (OSError, ValueError): pass @@ -226,9 +230,10 @@ def main(): elif args.stop: if item:run('docker','stop','--time','15',config['name']) elif args.start: - if not (args.directory/'state/auth.json').exists(): + if not (args.directory/'state/auth.json').exists() and not config.get('development_setup'): raise RuntimeError('Zugangseinrichtung unvollständig. Siehe INSTALL.md zur Wiederaufnahme.') - os.chown(args.directory/'state/auth.json',65534,65534) + if (args.directory/'state/auth.json').exists(): + os.chown(args.directory/'state/auth.json',65534,65534) if item:run('docker','start',config['name']) else:launch(config) ready(config);print('Deck bereit.') diff --git a/deploy/smoke.py b/deploy/smoke.py index ad3cf4d..7574fba 100644 --- a/deploy/smoke.py +++ b/deploy/smoke.py @@ -42,7 +42,7 @@ with patch('getpass.getpass',side_effect=lambda _:next(values)),patch('sys.stdin probe="""import json,sys,urllib.request v=json.load(sys.stdin) req=urllib.request.Request('http://127.0.0.1:8108/api/v1/status',headers={'Authorization':'Bearer '+v['token']}) -with urllib.request.urlopen(req,timeout=3) as r:assert json.load(r)['location']=='Server' +with urllib.request.urlopen(req,timeout=3) as r:assert json.load(r)['location']=='Athena-Debian' """ for _ in range(20): try:run('docker','exec','-i',NAME,'python3','-c',probe,data=json.dumps({'token':token}));break diff --git a/network-ui.js b/network-ui.js index 7ff0a07..1f1be67 100644 --- a/network-ui.js +++ b/network-ui.js @@ -29,7 +29,7 @@ function networkButtons(){ async function networkPage(){ const view=document.querySelector('#view'); if(!document.querySelector('#network-page')){ - view.innerHTML=`
EINSTELLUNGEN / NETZWERK

Dein Weg zu Athena.

Ein eigener WireGuard-Zugang für Athena Deck und seine internen API-Endpunkte.

WireGuard-Modul

Wird geprüft …

Auf Athena einrichten

Installiert WireGuard und Deck in einem eigenen Container. Der vorhandene Gateway bleibt unverändert. Die erste Einrichtung startet im LAN-Modus auf Port 8110.

Vor der Installation kopieren und sicher speichern. Dieser Token ist vom lokalen Mac-Zugang getrennt.

Benötigt den vorhandenen SSH-Zugang und Docker auf Athena. LAN-Zugriff verwendet HTTP; für vertrauliche Eingaben WireGuard oder SSH-Tunnel verwenden.

Zugriff auf Deck und API

Der lokale Mac-Zugang per SSH bleibt als Verwaltungskanal erhalten. Produktionsendpunkte werden nicht umgestellt. Im Modus „Nur Tunnel“ gibt es bei Tunnelausfall keinen LAN-Fallback.

`; + view.innerHTML=`
EINSTELLUNGEN / NETZWERK

Dein Weg zu Athena.

Ein eigener WireGuard-Zugang für Athena Deck und seine internen API-Endpunkte.

WireGuard-Modul

Wird geprüft …

Auf Athena einrichten

Installiert WireGuard und Deck in einem eigenen Container. Der vorhandene Gateway bleibt unverändert. Die erste Einrichtung startet im LAN-Modus auf Port 8110.

Vor der Installation kopieren und sicher speichern. Dieser Token gehört zur jeweiligen Server-Instanz.

Benötigt den vorhandenen SSH-Zugang und Docker auf Athena. LAN-Zugriff verwendet HTTP; für vertrauliche Eingaben WireGuard oder SSH-Tunnel verwenden.

Zugriff auf Deck und API

Der SSH-Zugang zum Debian-Server bleibt als Verwaltungskanal erhalten. Produktionsendpunkte werden nicht umgestellt. Im Modus „Nur Tunnel“ gibt es bei Tunnelausfall keinen LAN-Fallback.

`; document.querySelector('#network-install').onclick=()=>{const input=document.querySelector('#network-password'),password=input.value,token=document.querySelector('#network-api-token'),api_token=token.value;input.value='';token.value='';networkAction('install',{password,api_token});}; document.querySelector('#network-generate-token').onclick=()=>{document.querySelector('#network-api-token').value=accessToken();}; document.querySelector('#network-show-token').onclick=()=>{const input=document.querySelector('#network-api-token');input.type=input.type==='password'?'text':'password';document.querySelector('#network-show-token').textContent=input.type==='password'?'API-Token anzeigen':'API-Token verbergen';}; @@ -44,7 +44,7 @@ async function networkPage(){ const labels={'disabled-module':'Nicht angebunden',unavailable:'Nicht bereit',installing:'Installation läuft',disabled:'Deaktiviert',connecting:'Warte auf Handshake',connected:'Verbunden'}; document.querySelector('#network-state').textContent=labels[s.state]||'Nicht verfügbar'; const details=document.querySelector('#network-details');details.replaceChildren(); - for(const [label,value] of [['Konfiguration',s.configured?'Gespeichert':'Keine'],['Letzter Handshake',s.latest_handshake?new Date(s.latest_handshake*1000).toLocaleString('de-DE'):'Noch keiner'],['Dieser Zugang',s.ingress==='management'?'Mac / SSH-Verwaltung':s.ingress==='tunnel'?'WireGuard-Tunnel':'LAN']]){const d=document.createElement('div'),small=document.createElement('small'),strong=document.createElement('strong');small.textContent=label;strong.textContent=value;d.append(small,strong);details.append(d);} + for(const [label,value] of [['Konfiguration',s.configured?'Gespeichert':'Keine'],['Letzter Handshake',s.latest_handshake?new Date(s.latest_handshake*1000).toLocaleString('de-DE'):'Noch keiner'],['Dieser Zugang',s.ingress==='management'?'SSH-Verwaltung':s.ingress==='tunnel'?'WireGuard-Tunnel':'LAN']]){const d=document.createElement('div'),small=document.createElement('small'),strong=document.createElement('strong');small.textContent=label;strong.textContent=value;d.append(small,strong);details.append(d);} for(const [label,url] of [['LAN',s.lan_url],['Tunnel',s.tunnel_url]])if(url){const d=document.createElement('div'),a=document.createElement('a');a.href=url+'/#network';a.textContent=label+': '+url;a.target='_blank';a.rel='noopener';d.append(a);details.append(d);} document.querySelector('#network-setup').hidden=!!s.installed; document.querySelector('#network-config').hidden=false; diff --git a/network/README.md b/network/README.md index aaaeb34..98f00ea 100644 --- a/network/README.md +++ b/network/README.md @@ -6,7 +6,8 @@ Einstellungen → Netzwerk bietet Installation, Conf-Import, Aktivieren/Deaktivi Handshake-Status und die Modi **LAN**, **Tunnel**, **beides**. Diese Modi gelten für die Server-Instanz von Athena Deck und alle ihre `/api/v1/*`-Endpunkte. Produktive Router-, Modell-, Audio- und Bild-Endpunkte werden nicht übernommen. -Die lokale Mac-Instanz bleibt ein separater SSH-Verwaltungskanal. +Die aktuelle Debian-Entwicklungsinstanz verwendet dieses Modul noch nicht. +Die folgenden Angaben dokumentieren den separat getesteten Netzwerk-Prototyp. Die Implementierung benutzt einen eigenen Container `athena-deck-network` mit eigenem Netzwerk-Namespace. Im Container laufen ein eingeschränkter Root-Helper @@ -23,7 +24,7 @@ Port-Veröffentlichung; eine Aussage „keinerlei Netzwerkänderung“ wäre daf ## Einrichtung in der Oberfläche -1. Auf dem Mac http://127.0.0.1:8108/#network öffnen. +1. Die Verwaltungsoberfläche über den SSH-Tunnel öffnen (separater Netzwerk-Prototyp). 2. Eigenes Deck-Passwort (mindestens 16 Zeichen) und separaten API-Token (mindestens 32 Zeichen) vergeben, Token sichern und **Modul auf Athena installieren** wählen. Installation läuft asynchron und meldet ihren Status. @@ -33,7 +34,7 @@ Port-Veröffentlichung; eine Aussage „keinerlei Netzwerkänderung“ wäre daf führt zum Status „Verbunden“. Ein geladenes Interface alleine genügt nicht. 5. Gewünschten Zugriffsmodus testen, die Zieladresse öffnen, dort anmelden und innerhalb von 120 Sekunden bestätigen. Tunnel/beides muss über den Tunnel, - LAN über den LAN-Zugang bestätigt werden. Der Mac-Verwaltungskanal kann diese + LAN über den LAN-Zugang bestätigt werden. Der SSH-Verwaltungskanal kann diese Bestätigung nicht ersetzen. Ohne Bestätigung wird der vorige Modus wiederhergestellt. Gespeichert wird nur der @@ -62,7 +63,7 @@ gezielten Wiederherstellung liegen. Automatische Updates/Reparatur bestehender Installationen sind noch nicht implementiert. Der neue Server verwendet aktuell HTTP. WireGuard schützt den Tunneltransport. -Für Einrichtung und Secrets aus entfernten Netzen den lokalen Mac-Verwaltungskanal +Für Einrichtung und Secrets aus entfernten Netzen den lokalen SSH-Verwaltungskanal (SSH) verwenden. LAN-HTTP nur in einem vertrauenswürdigen Netz verwenden; HTTPS/Reverse-Proxy-Zertifikate sind noch nicht enthalten. Passwort wird mit PBKDF2-SHA256 (600.000 Iterationen, individuellem Salt) gespeichert. Sitzungen sind @@ -79,7 +80,8 @@ ssh -i /Users/mike_i386/.ssh/athena_key -o BatchMode=yes \ Dann http://127.0.0.1:8110 öffnen. Dieser Zugriff zählt als LAN, nicht als WireGuard-Bestätigung. Im Tunnel-only-Modus wird auch er gesperrt. -Die Mac-Oberfläche auf Port 8108 kann weiterhin per SSH den Helper verwalten. +Der frühere Remote-Verwaltungsadapter kann den Helper per SSH verwalten; +dieser Adapter ist in der Debian-Entwicklungsinstanz deaktiviert. Zur Wiederherstellung dort Modus LAN testen, SSH-Tunnel öffnen und dort bestätigen. Nur den neuen Container stoppen/starten: @@ -125,7 +127,7 @@ serverseitige Prüfung des tatsächlichen Zugangs gelten vor dem API-Aufruf. |---|---| | POST `/login` | `password` | | GET `/network` | Status ohne Secrets | -| POST `/network/install` | `password`, `api_token` für neue Server-Instanz, nur angemeldete Mac-Verwaltung | +| POST `/network/install` | `password`, `api_token` für neue Server-Instanz, nur angemeldete SSH-Verwaltung | | POST `/network/import` | `config` als Dateiinhalt | | POST `/network/connect` | `{}` | | POST `/network/disconnect` | `{}` | @@ -136,7 +138,7 @@ serverseitige Prüfung des tatsächlichen Zugangs gelten vor dem API-Aufruf. `/network` liefert `installed`, `configured`, `enabled`, `connected`, `latest_handshake`, `state`, `mode`, `pending`, `ingress`, URLs und ggf. Fehler. -Bei Nicht-Erreichbarkeit meldet die Mac-Ansicht ausdrücklich „noch nicht installiert +Bei Nicht-Erreichbarkeit meldet die Verwaltungsansicht ausdrücklich „noch nicht installiert oder nicht erreichbar“; sie behauptet nicht, den Unterschied sicher zu kennen. Anwendungsfehler geben HTTP 400, fehlende Sitzung 401, unerlaubter Host/Origin oder Zugangsweg 403. Installation läuft als Hintergrundauftrag mit `job.state`. diff --git a/server.py b/server.py index 7b74290..a5f3988 100644 --- a/server.py +++ b/server.py @@ -71,7 +71,7 @@ class HardwareProvider: self.checked = 0 def snapshot(self): - if os.environ.get('DECK_LOCAL_HARDWARE') == '1': + if os.environ.get('DECK_LOCAL_HARDWARE', '1') == '1': from collect_hardware import collect with self.lock: if self.cached is None or time.monotonic()-self.checked >= 5: @@ -218,7 +218,7 @@ class Handler(BaseHTTPRequestHandler): signed_in = self.authenticated(session_only=True) value = dict(initialized=record is not None, authenticated=signed_in) if signed_in: - value.update(api_token_configured=bool(record['api_token_hash']), password_changed_at=record['password_changed_at'], token_changed_at=record['token_changed_at'], account='Administrator', location=os.environ.get('DECK_LOCATION', 'Athena' if os.environ.get('DECK_AUTH_RPC') else 'Mac')) + value.update(api_token_configured=bool(record['api_token_hash']), password_changed_at=record['password_changed_at'], token_changed_at=record['token_changed_at'], account='Administrator', location=os.environ.get('DECK_LOCATION', 'Athena · Debian-Server')) return self.respond(value) def change_credentials(self, kind): @@ -262,7 +262,7 @@ class Handler(BaseHTTPRequestHandler): name, mime = routes[self.path] return self.respond((ROOT/name).read_bytes(), mime=mime) if self.path == '/api/v1/status': - return self.respond(dict(name='Athena Deck', version='0.4.0', state='ready', uptime_seconds=round(time.time()-self.server.started), mode='isolated', location=os.environ.get('DECK_LOCATION', 'Athena' if os.environ.get('DECK_AUTH_RPC') else 'Mac'), demo=self.server.demo.status())) + return self.respond(dict(name='Athena Deck', version='0.4.0', state='ready', uptime_seconds=round(time.time()-self.server.started), mode='isolated', location=os.environ.get('DECK_LOCATION', 'Athena · Debian-Server'), demo=self.server.demo.status())) if self.path == '/api/v1/hardware': return self.respond(self.server.hardware.snapshot()) if self.path == '/api/v1/network': diff --git a/test_server.py b/test_server.py index 321d8d3..c1b5152 100644 --- a/test_server.py +++ b/test_server.py @@ -48,7 +48,7 @@ class Tests(unittest.TestCase): self.assertEqual(e.exception.code,404) e.exception.close() def test_unavailable_hardware(self): - with patch('server.subprocess.run',side_effect=OSError()): + with patch.dict('os.environ', {'DECK_LOCAL_HARDWARE':'0'}), patch('server.subprocess.run',side_effect=OSError()): result=HardwareProvider().snapshot() self.assertFalse(result['available']) self.assertEqual(result['gpus'],[])