Files
management/docs/issues/0055-npm-scope-aufloesung-threadnet-web.md
T

97 lines
4.5 KiB
Markdown
Raw Normal View History

---
type: issue
id: "0055"
status: open
created: 2026-08-16
milestone: M2
priority: medium
area: security
related:
- "docs/issues/0054-ki-geraeuschunterdrueckung-element-call.md"
- "docs/adr/0018-ki-geraeuschunterdrueckung-clientseitig-opt-in.md"
- "docs/adr/0001-gitlab-kanonisch-push-mirror.md"
gitlab_iid: "39"
---
# Issue-0055: `@sorb`-Scope in ThreadNet-Web ist nirgends auf rohana festgelegt
## Problem / Motivation
`ThreadNet-Web` bezieht `@sorb/threadnet-call-embedded` aus der Gitea-npm-Registry auf rohana,
aber **im Repo steht nirgends, dass der Scope `@sorb` dorthin zeigt**. Es gibt weder eine
`.npmrc` im Wurzelverzeichnis noch in `apps/web`, und die CI setzt auch keine.
Dass es trotzdem funktioniert, liegt allein am Lockfile: `pnpm-lock.yaml` pinnt die vollständige
Tarball-URL
```
tarball: https://rohana.axion1337.de/api/packages/sorb/npm/%40sorb%2F…tgz
```
und die CI installiert mit `--frozen-lockfile`. Solange niemand die Version anhebt, wird der
Scope nie aufgelöst — und der fehlende Eintrag fällt nicht auf.
Aufgefallen beim Anheben auf `0.19.2-threadnet.8` (#0054): `pnpm install` griff nach
`registry.npmjs.org` und brach ab.
```
ERR_PNPM_FETCH_404 GET https://registry.npmjs.org/@sorb%2Fthreadnet-call-embedded: Not Found
```
Die Anhebung ging nur durch, weil der Scope für diesen einen Aufruf von Hand gesetzt wurde:
```sh
env 'npm_config_@sorb:registry=https://rohana.axion1337.de/api/packages/sorb/npm/' pnpm install
```
Das steht in keiner Doku. Der nächste, der die Abhängigkeit anhebt, läuft in dieselbe Wand.
## Warum das mehr ist als eine Unbequemlichkeit
Der heutige Fehlschlag ist **laut** — 404, Abbruch, niemand baut versehentlich etwas Falsches.
Laut ist gut. Der Punkt ist, dass die Lautstärke von einer Bedingung abhängt, die uns nicht
gehört: `@sorb/threadnet-call-embedded` existiert auf `registry.npmjs.org` **derzeit nicht**.
Registriert dort jemand diesen Namen, löst genau derselbe Befehl nicht mehr mit 404 auf, sondern
**erfolgreich — gegen ein fremdes Paket**. Das ist das Muster, das als *dependency confusion*
bekannt ist, und die Bedingung dafür ist nicht „ein Angriff auf uns", sondern „jemand legt einen
Scope-Namen an". Der Schutz besteht heute ausschließlich darin, dass ein Name auf einer fremden
Registry noch frei ist.
Verschärfend: Der Fehler träfe genau den Moment, in dem jemand eine Version anhebt — also den
Moment, in dem eine neue Abhängigkeit ohnehin erwartet wird und ein Download nicht auffällt.
Das ist dieselbe Klasse wie die Befunde aus #0054 und der Backup-Reihe: **die Absicherung besteht
nicht, sie ergibt sich nur zufällig aus dem aktuellen Zustand.** Sie „meldet" auch nichts — sie
funktioniert stillschweigend, bis sie es nicht mehr tut.
## Acceptance
- Eine **eingecheckte** `.npmrc` in `ThreadNet-Web` bindet den Scope fest:
`@sorb:registry=https://rohana.axion1337.de/api/packages/sorb/npm/`
- Ein Anheben der Version funktioniert im **frischen Klon ohne Zusatzschritte** — das ist der
eigentliche Nachweis, nicht das Vorhandensein der Datei.
- Gegenprobe: Ein Lauf mit absichtlich unerreichbarer rohana **scheitert**, statt auf
`registry.npmjs.org` auszuweichen.
- Die anderen Repos der Gruppe sind auf denselben Befund geprüft: Wer sonst noch `@sorb`-Pakete
zieht, hat dieselbe Lücke (`threadnet-call` selbst publisht nur, konsumiert aber ggf. auch).
- Der Auslieferungsweg in `ThreadNet-Web:docs/axion1337-fork.md` nennt den Befehl zum Anheben.
## Notes
**Kein Token nötig.** Der Lesezugriff auf die Registry ist anonym möglich (nachgeprüft: der
Paket-Index antwortet ohne Authentifizierung). Die `.npmrc` enthält damit **nur eine URL und kein
Geheimnis** und kann bedenkenlos eingecheckt werden — das ist der Grund, warum hier kein
Secrets-Handling dranhängt.
**Warum nicht einfach dokumentieren:** Ein Satz in der Fork-Doku würde den 404 erklären, aber die
`registry.npmjs.org`-Auflösung nicht verhindern. Nach der Lehre aus #0053 und dem Bindmount-Fall
ist Aufschreiben hier ausdrücklich **nicht** die Maßnahme: die Regel war beide Male vorhanden und
hat den Fehler nicht verhindert. Wirksam ist die eingecheckte Datei, weil sie den falschen Weg
gar nicht erst offen lässt.
**Verwandt, aber getrennt:** Bei der Gelegenheit ist aufgefallen, dass der Job `publish_npm` in
`threadnet-call` `allow_failure: true` trägt — ein *scheiternder* Publish färbt die Pipeline
nicht rot. Das ist ein eigener Befund und gehört nicht in dieses Issue; hier nur notiert, damit
er nicht verloren geht.