feat(quick-260914-eym): Mail-Transport je Versand nach Mandant (WINDOWS #30), ldap/digest/matching ueber Systemkontext, vier Tabellen im Werkzeug, Erlaubnisliste vollstaendig
- mail: MailerModule-Fabrik und DB-Startpfad (findFirst beim Boot) ersatzlos entfernt; MailService baut je Versand einen nodemailer-Transport aus getDecryptedSmtpConfig(tenantId) des Empfaenger-Mandanten, Umgebungs-Kette (MAIL_* -> TESSERA_SMTP_* -> localhost:1025) nur als Rueckfall; Fehler weiter verschluckt (T-02-12), close() im finally; neue mail.service.spec.ts (4 Tests, T-GWH-03 geschlossen) - settings: Startpfad-Methode samt vier Spec-Tests geloescht; auth: requestPasswordReset reicht user.tenantId durch (Spec-Zusicherung) - ldap: getAllActiveConfigs und Nachverschluesselung lesen ueber forSystem (zwei Zuweisungen), Schreibzeile je Altzeile ueber forTenant(config.tenantId); Tests 301/306 umgedreht, neuer Altzeilen-Test - tender-digest: Kandidatenabfrage ueber forSystem, Schleife gebunden (+1 Test) - tender-matching: Profilabfrage ueber forSystem, Katalog (D-03) ungebunden (+1 Test) - tender-notifications.integration.spec: Mock um forSystem - Werkzeug: LdapConfig (15 Spalten), LdapFieldMapping (6), TenderMatch (8), TenderSavedSearch (8) je neun Kennungen plus Relations-Kennung ldapconfig-systemkontext-include-fieldmappings-beider-mandanten -> Alle 253 Pruefungen bestanden - Detektor: FORSYSTEM_ALLOWED_CALL_SITES auf 4 Dateien / 5 Aufrufe; Proben-Empfaenger sysPrisma (Gate-Zaehlung, Name nicht hartkodiert) - Klassifikation: 6 Zeilen system-gebunden, settings/smtpConfig gebunden - Falsifizierung durch Rueckbau ausgefuehrt und zurueckgenommen: (a) FOR SELECT bei TenderMatch entfernt -> 5 von 253 rot (Insert gelingt, cmd ALL); (b) Regel TenderSavedSearch aus der Datei entfernt -> 1 von 245 rot (Extraktion), lebende DB bleibt bei 34; (c) local=false -> gruen, plus Reset entfernt -> 5 rot (Erben sichtbar); (d) Zahl 0 -> 2 rot, Fremddatei admin-seed -> 3 rot - Baseline: 64 Dateien / 1054 Tests, tsc 0, Werkzeug 253 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
This commit is contained in:
@@ -7,11 +7,13 @@ import { forTenant } from '../prisma/prisma-tenant.extension';
|
||||
* SettingsService.spec — NEU (260911-gwh). Der Bereich `settings` hatte VOR
|
||||
* diesem Lauf KEINE Testdatei (Befund J). Zwei-Klienten-Nachbau, aber mit
|
||||
* einer GRENZE als Bauform (anders als `favorites`): der UNGEBUNDENE Nachbau
|
||||
* bietet fuer `smtpConfig` AUSSCHLIESSLICH `findFirst` (der Startpfad) —
|
||||
* KEIN `findUnique`, KEIN `upsert`; der GEBUNDENE Klient bietet
|
||||
* AUSSCHLIESSLICH `findUnique`/`upsert` — KEIN `findFirst`. Ein gebundener
|
||||
* Startpfad scheitert damit ebenso hart wie ein ungebundener Anfrageweg
|
||||
* ("X is not a function" statt eines stillen Fallbacks).
|
||||
* bietet fuer `smtpConfig` AUSSCHLIESSLICH `findFirst` — KEIN `findUnique`,
|
||||
* KEIN `upsert`; der GEBUNDENE Klient bietet AUSSCHLIESSLICH
|
||||
* `findUnique`/`upsert` — KEIN `findFirst`. Ein ungebundener Anfrageweg
|
||||
* scheitert damit hart ("X is not a function" statt eines stillen
|
||||
* Fallbacks). Der ungebundene Startpfad des Mailmoduls (findFirst beim
|
||||
* Boot) und sein describe-Block sind seit 260914-eym (WINDOWS #30)
|
||||
* GELOESCHT — der ungebundene Nachbau bleibt als Falsifizierungsform stehen.
|
||||
*
|
||||
* `nodemailer` wird per `vi.mock` ersetzt — kein echter Transport (lokal
|
||||
* gibt es keinen `mailhog`).
|
||||
@@ -416,88 +418,6 @@ describe('SettingsService — Bindung an forTenant() (260911-gwh)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadAnySmtpConfigForStartupTransport (Startpfad, bewusst ungebunden)', () => {
|
||||
it('laeuft ueber den UNGEBUNDENEN Nachbau (findFirst), liefert secure/requireTLS/entschluesseltes Kennwort', async () => {
|
||||
const prisma = makeFakePrisma([
|
||||
{
|
||||
id: 'smtp-a',
|
||||
tenantId: 't1',
|
||||
host: 'smtp-a.example.invalid',
|
||||
port: 465,
|
||||
encryption: 'ssl-tls',
|
||||
username: 'user-a',
|
||||
encryptedPassword: 'enc(geheim)',
|
||||
fromAddress: 'a@example.invalid',
|
||||
},
|
||||
]);
|
||||
const crypto = makeFakeCrypto();
|
||||
const service = new SettingsService(prisma as any, crypto as any);
|
||||
|
||||
const result = await service.loadAnySmtpConfigForStartupTransport();
|
||||
|
||||
expect(result).toEqual({
|
||||
host: 'smtp-a.example.invalid',
|
||||
port: 465,
|
||||
secure: true,
|
||||
requireTLS: false,
|
||||
username: 'user-a',
|
||||
password: 'geheim',
|
||||
fromAddress: 'a@example.invalid',
|
||||
});
|
||||
});
|
||||
|
||||
it('requireTLS bei starttls', async () => {
|
||||
const prisma = makeFakePrisma([
|
||||
{
|
||||
id: 'smtp-a',
|
||||
tenantId: 't1',
|
||||
host: 'smtp-a.example.invalid',
|
||||
port: 587,
|
||||
encryption: 'starttls',
|
||||
username: null,
|
||||
encryptedPassword: null,
|
||||
fromAddress: 'a@example.invalid',
|
||||
},
|
||||
]);
|
||||
const service = new SettingsService(prisma as any, makeFakeCrypto() as any);
|
||||
|
||||
const result = await service.loadAnySmtpConfigForStartupTransport();
|
||||
|
||||
expect(result?.secure).toBe(false);
|
||||
expect(result?.requireTLS).toBe(true);
|
||||
});
|
||||
|
||||
it('leerer Nachbau -> null', async () => {
|
||||
const prisma = makeFakePrisma([]);
|
||||
const service = new SettingsService(prisma as any, makeFakeCrypto() as any);
|
||||
|
||||
const result = await service.loadAnySmtpConfigForStartupTransport();
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('Null-Klienten-Nachweis: der Startpfad erzeugt KEINEN gebundenen Klienten (gemessen, nicht behauptet)', async () => {
|
||||
const prisma = makeFakePrisma([
|
||||
{
|
||||
id: 'smtp-a',
|
||||
tenantId: 't1',
|
||||
host: 'smtp-a.example.invalid',
|
||||
port: 587,
|
||||
encryption: 'starttls',
|
||||
username: null,
|
||||
encryptedPassword: null,
|
||||
fromAddress: 'a@example.invalid',
|
||||
},
|
||||
]);
|
||||
const service = new SettingsService(prisma as any, makeFakeCrypto() as any);
|
||||
|
||||
vi.mocked(forTenant).mockClear();
|
||||
await service.loadAnySmtpConfigForStartupTransport();
|
||||
|
||||
expect(vi.mocked(forTenant).mock.calls.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Wachhund je Anfrageweg', () => {
|
||||
const storedRow: FakeSmtpRow = {
|
||||
id: 'smtp-a',
|
||||
|
||||
Reference in New Issue
Block a user