// Odoo settings from Connections: login checked before saving, stored encrypted, key never returned, env fallback. import { test } from "node:test"; import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "quorla-odoo-")); const FILE = path.join(TMP, "connections.json"); Object.assign(process.env, { QUORLA_CONNECTIONS_FILE: FILE, DASHBOARD_SECRET: "s".repeat(32), QUORLA_DASHBOARD_DATA: path.join(TMP, "dash"), ODOO_URL: "", ODOO_API_KEY: "" }); const odoo = await import("../../dashboard/server/odoo.js"); test("save checks the login, stores it sealed and hides the key; disconnect clears it", async () => { const realFetch = globalThis.fetch; const calls = []; globalThis.fetch = async (url, init) => { const { params } = JSON.parse(init.body); calls.push({ url: String(url), params }); const ok = params.args[2] === "good-key"; return new Response(JSON.stringify({ result: params.method === "login" ? (ok ? 7 : false) : null })); }; try { assert.equal(odoo.settings().configured, false); const form = { url: "https://acme.odoo.com/odoo/action-1", db: "acme", username: "ops@acme.test", allowWrites: true }; await assert.rejects(odoo.saveSettings({ ...form, apiKey: "bad-key" }, "Ana"), /rejected the login/); await assert.rejects(odoo.saveSettings({ ...form, apiKey: "" }, "Ana"), /required/); const s = await odoo.saveSettings({ ...form, apiKey: "good-key" }, "Ana"); assert.equal(calls.at(-1).url, "https://acme.odoo.com/jsonrpc", "address trimmed to the site root"); assert.deepEqual([s.configured, s.source, s.url, s.allowWrites, s.updatedBy], [true, "settings", "https://acme.odoo.com", true, "Ana"]); assert.equal(JSON.stringify(s).includes("good-key"), false); assert.equal(fs.readFileSync(FILE, "utf8").includes("good-key"), false, "key encrypted at rest"); const again = await odoo.saveSettings({ ...form, apiKey: "", allowWrites: false }, "Ana"); assert.equal(again.allowWrites, false, "empty key keeps the stored one"); assert.equal(odoo.removeSettings().configured, false); } finally { globalThis.fetch = realFetch; } });