// The mail transport registry (ENGAGEMENT.md §3.1) and the one transport core // ships. The registry's job is that `credentialFields` is the single declaration // the admin form, the sanitizer and the "is it a secret" answer all read — so // most of what is asserted here is that nothing else knows a field name. process.env.SECRET_ENC_KEY = process.env.SECRET_ENC_KEY || 'unit-test-enc-key' process.env.DB_HOST = '127.0.0.1' process.env.DB_PORT = '59999' const { test, after } = require('node:test') const assert = require('node:assert/strict') const { transports } = require('../src/engagement') const db = require('../src/utils/db') after(() => db.close()) const SMTP_CRED = { host: 'relay.example.com', port: 587, secure: false, user: 'apikey', password: 'sec' } test('requiring the subsystem is what registers core\'s transports', () => { assert.equal(transports.has('smtp'), true) const [smtp] = transports.describe() assert.equal(smtp.id, 'smtp') assert.ok(smtp.credentialFields.length > 0) }) test('describe() carries no functions and no secret values', () => { const [smtp] = transports.describe() assert.equal(typeof smtp.build, 'undefined') assert.equal(typeof smtp.isComplete, 'undefined') const password = smtp.credentialFields.find((f) => f.key === 'password') assert.equal(password.kind, 'secret') assert.equal('value' in password, false) }) test('sanitizeCredential drops undeclared keys', () => { const out = transports.sanitizeCredential('smtp', { ...SMTP_CRED, evil: 'x' }) assert.deepEqual(Object.keys(out).sort(), ['host', 'password', 'port', 'secure', 'user']) }) test('sanitizeCredential coerces to the declared kind', () => { const out = transports.sanitizeCredential('smtp', { host: 'relay.example.com', port: '587', secure: 'yes' }) assert.equal(out.port, 587) assert.equal(out.secure, true) }) test('an empty secret is omitted, so a merge keeps the stored one', () => { const patch = transports.sanitizeCredential('smtp', { ...SMTP_CRED, password: '' }) assert.equal('password' in patch, false) const merged = transports.mergeCredential('smtp', { password: 'stored' }, patch) assert.equal(merged.password, 'stored') }) test('publicCredential and secretsPresent split the blob the way the API needs', () => { assert.deepEqual(transports.publicCredential('smtp', SMTP_CRED), { host: 'relay.example.com', port: 587, secure: false, user: 'apikey', }) assert.deepEqual(transports.secretsPresent('smtp', SMTP_CRED), { password: true }) assert.deepEqual(transports.secretsPresent('smtp', { host: 'x' }), { password: false }) }) test('an unknown transport is a safe no-op everywhere, never a throw', () => { assert.equal(transports.get('nope'), null) assert.equal(transports.isComplete('nope', SMTP_CRED), false) assert.deepEqual(transports.sanitizeCredential('nope', SMTP_CRED), {}) assert.deepEqual(transports.publicCredential('nope', SMTP_CRED), {}) assert.deepEqual(transports.secretsPresent('nope', SMTP_CRED), {}) }) // ── smtp's own completeness rule ──────────────────────────────────────────── test('smtp needs a destination, and auth is all-or-nothing', () => { assert.equal(transports.isComplete('smtp', SMTP_CRED), true) // A local MTA needs no credentials at all. assert.equal(transports.isComplete('smtp', { host: 'mta.example.com', port: 25 }), true) // A username with no password authenticates as nobody and fails at the server. assert.equal(transports.isComplete('smtp', { host: 'relay.example.com', port: 587, user: 'apikey' }), false) assert.equal(transports.isComplete('smtp', { port: 587 }), false) assert.equal(transports.isComplete('smtp', {}), false) }) test('smtp declares no default host — §3.2 rule 1, as a test', () => { const [smtp] = transports.describe() const host = smtp.credentialFields.find((f) => f.key === 'host') assert.equal(host.default, null) assert.equal(host.required, true) }) // ── registration is validated at the call ─────────────────────────────────── test('registration rejects a bad shape and a collision', () => { const ok = { id: 'fake', label: 'Fake', credentialFields: [{ key: 'k', kind: 'text' }], build: () => {}, isComplete: () => true } assert.throws(() => transports.registerMailTransport({ ...ok, id: 'Not Valid' }), /invalid id/) assert.throws(() => transports.registerMailTransport({ ...ok, label: '' }), /label required/) assert.throws(() => transports.registerMailTransport({ ...ok, credentialFields: [] }), /credentialFields required/) assert.throws(() => transports.registerMailTransport({ ...ok, credentialFields: [{ key: 'k', kind: 'wat' }] }), /unknown kind/) assert.throws(() => transports.registerMailTransport({ ...ok, build: undefined }), /build\(\) required/) assert.throws(() => transports.registerMailTransport({ ...ok, id: 'smtp' }), /already registered/) }) test('a registered transport is a copy — a caller cannot mutate the catalog afterwards', () => { const fields = [{ key: 'k', label: 'K', kind: 'text', required: true }] transports.registerMailTransport({ id: 'tamper', label: 'Tamper', credentialFields: fields, build: () => {}, isComplete: () => true, }) fields[0].kind = 'secret' const def = transports.describe().find((t) => t.id === 'tamper') assert.equal(def.credentialFields[0].kind, 'text') })