import assert from 'node:assert/strict'; import { mkdtempSync, readFileSync, statSync } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; import { test } from 'node:test'; test('Dovecot preparation creates a private secret and Maildir root', () => { const projectDir = mkdtempSync(path.join(tmpdir(), 'mailhub-dovecot-prepare-')); const result = spawnSync('bash', ['scripts/prepare-dovecot.sh'], { cwd: path.resolve(import.meta.dirname, '..'), env: { ...process.env, MAILHUB_PROJECT_DIR: projectDir }, encoding: 'utf8' }); const unsupportedLinuxUid = process.platform === 'linux' && typeof process.getuid === 'function' && ![0, 1000].includes(process.getuid()); if (unsupportedLinuxUid) { assert.notEqual(result.status, 0); assert.match(result.stderr, /must run as root or host uid 1000/); return; } assert.equal(result.status, 0, result.stderr || result.stdout); const secretPath = path.join(projectDir, 'data', 'secrets', 'dovecot_auth_secret'); const webmailSecretPath = path.join(projectDir, 'data', 'secrets', 'webmail_sso_secret'); const maildirRoot = path.join(projectDir, 'data', 'maildir'); const secretStat = statSync(secretPath); assert.equal(secretStat.isFile(), true); assert.equal(secretStat.mode & 0o777, 0o400); assert.equal(statSync(webmailSecretPath).isFile(), true); assert.equal(statSync(webmailSecretPath).mode & 0o777, 0o440); assert.equal(statSync(path.dirname(webmailSecretPath)).mode & 0o777, 0o750); assert.notEqual(readFileSync(secretPath, 'utf8'), readFileSync(webmailSecretPath, 'utf8')); assert.equal(statSync(maildirRoot).isDirectory(), true); assert.equal(statSync(maildirRoot).mode & 0o777, 0o700); });