raw fetch: externer Abrufbefehl pro Instanz (.wikitool-fetch.json) als Andockstelle für einen Auth-Dienst #169

Open
opened 2026-10-02 20:01:45 +00:00 by torben · 0 comments
Owner

Problem

raw fetch (#120) lädt nur ohne Login: kein Cookie, kein JavaScript. Für Paywall-Seiten bringt #120 die Option --html mit - der Mensch speichert die Seite aus seinem eingeloggten Browser, und raw fetch leitet daraus ab. Das reicht für den Einzelfall, verlangt aber pro Artikel Handarbeit am Desktop.

Ein Auth-Dienst, der Sessions hält und "URL rein, HTML raus" beantwortet, soll außerhalb dieses Stacks entstehen (Notizen dazu: #87). wikitool selbst bekommt keine Zugangsdaten, keine Login-Adapter und keine Headless-Browser-Abhängigkeit: Das Tool geht an jede Instanz, und Zugangsdaten haben im Arbeitsbaum nichts zu suchen (raw/CONTRACT.md § What does not belong here). Was fehlt, ist die Stelle, an der eine Instanz einen solchen Dienst einhängt.

Entwurf

  1. Konfiguration .wikitool-fetch.json im Instanz-Root, gitignored, optional - gleiches Muster wie .wikitool-upload.json (Konstante in tools/chemenu/config.py, Eintrag in .gitignore, Ignore-Kanarie in docs verify, Zeile in doctor):
    {
      "fetchers": [
        {"name": "auth-proxy", "hosts": ["heise.de", "*.heise.de"], "command": ["/usr/local/bin/auth-fetch"]}
      ]
    }
    
    Ohne Datei verhält sich raw fetch exakt wie nach #120.
  2. Auswahl: Der erste Eintrag, dessen hosts auf den Host der URL passt (exakt oder *.-Suffix), wird benutzt; sonst der eingebaute urllib-Abruf. Keine Kaskade: Schlägt der externe Befehl fehl, fällt raw fetch nicht auf den eingebauten Abruf zurück - der lieferte genau den Teaser, den der Fetcher vermeiden soll.
  3. Protokoll mit dem Befehl: Aufruf als command + [url], ohne Shell (subprocess.run(list)). Exit 0 und HTML-Bytes auf stdout = Erfolg; alles andere = exit 1 von raw fetch, stderr des Befehls wird mit ausgegeben, nichts wird nach incoming/ geschrieben. Timeout und Größenlimit aus #120 gelten unverändert.
  4. Ergebnis wie bei #120: dasselbe Bundle <stem>.html (stdout-Bytes unverändert) + <stem>.md. Im Header fetched_by: wikitool raw fetch (fetcher: <name>); http_status/final_url entfallen, weil der Befehl sie nicht liefert.
  5. Wer die Datei schreibt: nur der Nutzer, nie ein Agent - sie benennt ein Programm, das wikitool ausführt. Dieselbe Haltung wie bei .wikitool-remotes.json; steht in raw/CONTRACT.md und im ON FAILURE-Text.
  6. MCP bleibt außen vor (wie #120 Entscheidung 12).

Nicht blockierend, beim Bau zu prüfen: Soll der Befehl optional einen Content-Type zurückgeben können (z. B. PDF hinter Login)? Wenn ein echter Dienst das braucht, als zweite Ausgabezeile auf stderr oder per JSON-Modus nachziehen; sonst nur HTML.

Betroffene Dateien

  • tools/chemenu/config.py, tools/chemenu/commands/raw_cmd.py bzw. das Modul aus #120 (web_capture.py), Kommando-Record von raw fetch
  • .gitignore, tools/chemenu/commands/docs_verify.py (Ignore-Kanarie), tools/chemenu/commands/doctor.py (vorhanden/fehlt/kaputt)
  • tools/chemenu/tests/test_raw_fetch.py - Fetcher als kleines Python-Skript im Testverzeichnis
  • raw/CONTRACT.md, tools/README.md

Akzeptanzkriterien

  • Ohne .wikitool-fetch.json erzeugt raw fetch byte-identische Ausgaben wie vorher (#120-Tests unverändert grün).
  • Mit einem passenden Eintrag ist incoming/<stem>.html byte-identisch mit dem stdout des Befehls, und der eingebaute Abruf wird nicht ausgeführt (Testserver erhält keinen Request).
  • Ein Befehl mit exit ≠ 0 führt zu exit 1, gibt dessen stderr aus und hinterlässt keine Datei in incoming/; der eingebaute Abruf wird nicht als Ersatz versucht.
  • Eine URL, deren Host auf keinen Eintrag passt, geht über den eingebauten Abruf.
  • .wikitool-fetch.json ist gitignored (docs verify-Kanarie), doctor meldet vorhanden/fehlt/fehlerhaft, ohne zu FAILen.
  • pytest, docs verify, instructions verify grün; CI grün.

Versionsteil

--minor - neue optionale Datei, die eine ältere Version ignoriert; ohne sie keine Verhaltensänderung. Drop-in in beide Richtungen.

Auslöser (prio/waiting)

Beides muss erfüllt sein:

  1. #120 ist gebaut (dieses Issue erweitert dessen Kommando).
  2. Ein Auth-Dienst nach #87 existiert und kann als Befehl aufgerufen werden. Vorher fehlt der Gegenpol zum Testen des Protokolls an einem echten Fall; das Protokoll (Punkt 3) wird dann gegen ihn geprüft und hier korrigiert, falls nötig.
## Problem `raw fetch` (#120) lädt nur ohne Login: kein Cookie, kein JavaScript. Für Paywall-Seiten bringt #120 die Option `--html` mit - der Mensch speichert die Seite aus seinem eingeloggten Browser, und `raw fetch` leitet daraus ab. Das reicht für den Einzelfall, verlangt aber pro Artikel Handarbeit am Desktop. Ein Auth-Dienst, der Sessions hält und "URL rein, HTML raus" beantwortet, soll außerhalb dieses Stacks entstehen (Notizen dazu: #87). `wikitool` selbst bekommt **keine** Zugangsdaten, keine Login-Adapter und keine Headless-Browser-Abhängigkeit: Das Tool geht an jede Instanz, und Zugangsdaten haben im Arbeitsbaum nichts zu suchen (`raw/CONTRACT.md` § What does not belong here). Was fehlt, ist die Stelle, an der eine Instanz einen solchen Dienst einhängt. ## Entwurf 1. **Konfiguration `.wikitool-fetch.json`** im Instanz-Root, gitignored, optional - gleiches Muster wie `.wikitool-upload.json` (Konstante in `tools/chemenu/config.py`, Eintrag in `.gitignore`, Ignore-Kanarie in `docs verify`, Zeile in `doctor`): ```json { "fetchers": [ {"name": "auth-proxy", "hosts": ["heise.de", "*.heise.de"], "command": ["/usr/local/bin/auth-fetch"]} ] } ``` Ohne Datei verhält sich `raw fetch` exakt wie nach #120. 2. **Auswahl:** Der erste Eintrag, dessen `hosts` auf den Host der URL passt (exakt oder `*.`-Suffix), wird benutzt; sonst der eingebaute `urllib`-Abruf. Keine Kaskade: Schlägt der externe Befehl fehl, fällt `raw fetch` **nicht** auf den eingebauten Abruf zurück - der lieferte genau den Teaser, den der Fetcher vermeiden soll. 3. **Protokoll mit dem Befehl:** Aufruf als `command + [url]`, ohne Shell (`subprocess.run(list)`). Exit 0 und HTML-Bytes auf stdout = Erfolg; alles andere = exit 1 von `raw fetch`, stderr des Befehls wird mit ausgegeben, nichts wird nach `incoming/` geschrieben. Timeout und Größenlimit aus #120 gelten unverändert. 4. **Ergebnis wie bei #120:** dasselbe Bundle `<stem>.html` (stdout-Bytes unverändert) + `<stem>.md`. Im Header `fetched_by: wikitool raw fetch (fetcher: <name>)`; `http_status`/`final_url` entfallen, weil der Befehl sie nicht liefert. 5. **Wer die Datei schreibt:** nur der Nutzer, nie ein Agent - sie benennt ein Programm, das `wikitool` ausführt. Dieselbe Haltung wie bei `.wikitool-remotes.json`; steht in `raw/CONTRACT.md` und im ON FAILURE-Text. 6. **MCP bleibt außen vor** (wie #120 Entscheidung 12). Nicht blockierend, beim Bau zu prüfen: Soll der Befehl optional einen Content-Type zurückgeben können (z. B. PDF hinter Login)? Wenn ein echter Dienst das braucht, als zweite Ausgabezeile auf stderr oder per JSON-Modus nachziehen; sonst nur HTML. ## Betroffene Dateien - `tools/chemenu/config.py`, `tools/chemenu/commands/raw_cmd.py` bzw. das Modul aus #120 (`web_capture.py`), Kommando-Record von `raw fetch` - `.gitignore`, `tools/chemenu/commands/docs_verify.py` (Ignore-Kanarie), `tools/chemenu/commands/doctor.py` (vorhanden/fehlt/kaputt) - `tools/chemenu/tests/test_raw_fetch.py` - Fetcher als kleines Python-Skript im Testverzeichnis - `raw/CONTRACT.md`, `tools/README.md` ## Akzeptanzkriterien - [ ] Ohne `.wikitool-fetch.json` erzeugt `raw fetch` byte-identische Ausgaben wie vorher (#120-Tests unverändert grün). - [ ] Mit einem passenden Eintrag ist `incoming/<stem>.html` byte-identisch mit dem stdout des Befehls, und der eingebaute Abruf wird nicht ausgeführt (Testserver erhält keinen Request). - [ ] Ein Befehl mit exit ≠ 0 führt zu exit 1, gibt dessen stderr aus und hinterlässt keine Datei in `incoming/`; der eingebaute Abruf wird nicht als Ersatz versucht. - [ ] Eine URL, deren Host auf keinen Eintrag passt, geht über den eingebauten Abruf. - [ ] `.wikitool-fetch.json` ist gitignored (`docs verify`-Kanarie), `doctor` meldet vorhanden/fehlt/fehlerhaft, ohne zu FAILen. - [ ] `pytest`, `docs verify`, `instructions verify` grün; CI grün. ## Versionsteil **`--minor`** - neue optionale Datei, die eine ältere Version ignoriert; ohne sie keine Verhaltensänderung. Drop-in in beide Richtungen. ## Auslöser (`prio/waiting`) Beides muss erfüllt sein: 1. #120 ist gebaut (dieses Issue erweitert dessen Kommando). 2. Ein Auth-Dienst nach #87 existiert und kann als Befehl aufgerufen werden. Vorher fehlt der Gegenpol zum Testen des Protokolls an einem echten Fall; das Protokoll (Punkt 3) wird dann gegen ihn geprüft und hier korrigiert, falls nötig.
torben added the prio/waitingsize/Marea/kbkind/build labels 2026-10-02 20:01:45 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#169