Skip to content

refactor(types): Renderer/Main-Grenze schliessen und bewachen - #27

Merged
Baldri merged 1 commit into
mainfrom
claude/session/refactor/mingly-renderer-main-boundary
Aug 28, 2026
Merged

refactor(types): Renderer/Main-Grenze schliessen und bewachen#27
Baldri merged 1 commit into
mainfrom
claude/session/refactor/mingly-renderer-main-boundary

Conversation

@Baldri

@Baldri Baldri commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Was

Die letzten vier Stellen, an denen der Renderer Typen aus dem Electron-Hauptprozess importierte, sind aufgelöst — und ein Test hält die Grenze künftig geschlossen.

Warum das kein Stilthema ist

tsconfig.json deckt nur src/renderer, src/shared und src/preload ab. TypeScript folgt Importen aber über die Grenze hinaus. Jeder solche Import pfropft ein Stück des Hauptprozess-Modulgraphen auf den Typecheck des Renderers — und dieses Pfropfreis wächst von selbst, sobald die Hauptprozess-Datei einen neuen Import bekommt.

Genau das ist passiert: Der Guard-Import in hybrid-orchestrator.ts (#26) verlängerte den Typgraphen des Renderers über orchestrator-store.ts bis in src/main/database/index.ts, dessen sql.js-Abhängigkeit keine Typen mitbringt und für die kein @types-Paket installiert ist. npm run typecheck fiel mit TS7016 — in einer Datei, die niemand angefasst hatte.

Änderungen

RiskLevel, SensitiveDataType, SensitiveDataMatch, SensitiveDataScanResult und UploadPermissionRequest liegen jetzt in src/shared/privacy-types.ts. Der letzte bettet ein Scan-Ergebnis ein, die fünf sind also ein Cluster, und keiner hängt an Hauptprozess-Code. Beide definierenden Module re-exportieren die Namen, bestehende Importeure bleiben unverändert.

Der Wächter ist der wichtigere Teil. Eine einzelne Importzeile fällt im Review nicht auf, und der Fehler, den sie verursacht, taucht ganz woanders auf — in einer Datei, die der Autor nie geöffnet hat. tests/unit/renderer-process-boundary.test.ts durchsucht jede Renderer-Quelle und meldet Datei, Zeile und was zu tun ist.

Tests

npm test1411 passed | 29 skipped (95 Dateien), Exit 0 · npm run typecheck → Exit 0 · build:main und build:renderer → Exit 0

Kein bestehender Test verändert.

Nachweis, dass der Wächter diskriminiert — beide Importformen:

Sabotage Ergebnis
statisches from '../../main/security/...' in einen Store geschmuggelt rot, mit Fundstelle
dynamisches import('../../main/database/index') rot, mit Fundstelle

Und der Grep-Nachweis mit Positivkontrolle im selben Lauf: null Übergriffe, während dieselbe Suche die neuen shared-Importe findet. Ein Nullbefund ohne Positivkontrolle wäre keiner.

Review-Punkte

Der Wächter arbeitet auf dem Quelltext, mit einem regulären Ausdruck über Import- und import()-Formen. Das ist bewusst: er liest ein paar Dutzend Dateien, braucht keine Transformation und hängt an keiner Uhr. Eine exotische Schreibweise — etwa ein über eine Konstante zusammengesetzter Pfad — würde er übersehen; dagegen steht der erste Test, der sicherstellt, dass er überhaupt Dateien findet.

Die Grenze gilt in eine Richtung. src/main darf weiterhin aus src/shared lesen, und das tut es. Geprüft wird nur, dass der Renderer nicht in den Hauptprozess greift.

preload ist nicht abgedeckt. Dort wäre ein Import aus main architektonisch ebenfalls fragwürdig, aber es gibt heute keinen, und ich habe die Prüfung nicht auf Verdacht ausgeweitet.

🤖 Generated with Claude Code

`tsconfig.json` covers only src/renderer, src/shared and src/preload, but
TypeScript follows imports past that boundary. Four renderer files imported
types straight from src/main, and each one grafted a piece of the main-process
module graph onto the renderer's type-check — a graft that grows on its own
whenever the main-process file gains an import.

That is not hypothetical. A guard import added to hybrid-orchestrator.ts (#26)
extended the renderer's graph through orchestrator-store.ts down to
src/main/database/index.ts, whose `sql.js` dependency ships no types and has no
@types package installed. `npm run typecheck` failed with TS7016 in a file
nobody had edited.

`RiskLevel`, `SensitiveDataType`, `SensitiveDataMatch`,
`SensitiveDataScanResult` and `UploadPermissionRequest` move to
`src/shared/privacy-types.ts` — the last of these embeds a scan result, so the
five are one cluster and none of them touches main-process code. Both defining
modules re-export the names, so main-process importers are unchanged.

The guard matters more than the move. A single import line will not be caught
in review, and the failure it causes surfaces somewhere else entirely — in a
file the author never opened. `tests/unit/renderer-process-boundary.test.ts`
scans every renderer source and fails with the offending file, the offending
line, and what to do about it.

Verified to discriminate, both import forms:
- a static `from '../../main/...'` smuggled into a renderer store -> red
- a dynamic `import('../../main/...')` -> red, same test

1411 tests green, typecheck exit 0, build:main and build:renderer exit 0.
grep over src/renderer finds no boundary crossing, with a positive control in
the same run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Baldri
Baldri merged commit 00e7e0b into main Aug 28, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant