import assert from "node:assert/strict"; import { mkdtemp, readFile, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import test from "node:test"; import { createFoundryAgentStore } from "./foundry-agent-store.mjs"; test("Foundry agent setup issues separate durable credentials and revoke closes both", async () => { const dataRoot = await mkdtemp(path.join(os.tmpdir(), "nodedc-foundry-agent-store-")); let currentTime = Date.parse("2026-07-18T12:00:00.000Z"); const store = createFoundryAgentStore({ dataRoot, now: () => currentTime }); try { const created = await store.createAgent({ ownerId: "user_root", ownerKey: "dcctouch@gmail.com", name: "Foundry Codex", }); assert.equal(created.status, "active"); assert.equal(created.deviceCount, 0); assert.equal((await store.listAgents("another@nodedc.local")).length, 0); const setup = await store.issueSetupCode("dcctouch@gmail.com", created.id); const redeemed = await store.redeemSetupCode(setup.code, "Mac Pro Codex Desktop"); assert.match(redeemed.foundryToken, /^fnda_/); assert.match(redeemed.ontologyToken, /^fndo_/); assert.notEqual(redeemed.foundryToken, redeemed.ontologyToken); assert.equal(redeemed.device.revokedAt, null); assert.equal(Object.hasOwn(redeemed.device, "foundryTokenHash"), false); assert.equal(Object.hasOwn(redeemed.device, "ontologyTokenHash"), false); await assert.rejects( () => store.redeemSetupCode(setup.code, "Replay"), /setup_code_already_redeemed/, ); const foundrySession = await store.authenticateFoundryToken(redeemed.foundryToken, { check: true }); const ontologySession = await store.authenticateOntologyToken(redeemed.ontologyToken, { check: true }); assert.equal(foundrySession.actor.actorId, "user_root"); assert.equal(ontologySession.actor.ownerKey, "dcctouch@gmail.com"); assert.equal(await store.authenticateFoundryToken(redeemed.ontologyToken), null); assert.equal(await store.authenticateOntologyToken(redeemed.foundryToken), null); currentTime += 3 * 365 * 24 * 60 * 60_000; assert.ok(await store.authenticateFoundryToken(redeemed.foundryToken)); assert.ok(await store.authenticateOntologyToken(redeemed.ontologyToken)); const revoked = await store.revokeAgent("dcctouch@gmail.com", created.id); assert.equal(revoked.status, "revoked"); assert.equal(await store.authenticateFoundryToken(redeemed.foundryToken), null); assert.equal(await store.authenticateOntologyToken(redeemed.ontologyToken), null); const persisted = await readFile(path.join(dataRoot, "agents.json"), "utf8"); assert.equal(persisted.includes(redeemed.foundryToken), false); assert.equal(persisted.includes(redeemed.ontologyToken), false); } finally { await rm(dataRoot, { recursive: true, force: true }); } }); test("Foundry setup codes expire and cannot cross owner boundaries", async () => { const dataRoot = await mkdtemp(path.join(os.tmpdir(), "nodedc-foundry-agent-expiry-")); let currentTime = Date.parse("2026-07-18T12:00:00.000Z"); const store = createFoundryAgentStore({ dataRoot, now: () => currentTime }); try { const agent = await store.createAgent({ ownerId: "user_root", ownerKey: "owner@nodedc.local", name: "Owner agent" }); await assert.rejects(() => store.issueSetupCode("other@nodedc.local", agent.id), /foundry_agent_not_found/); const setup = await store.issueSetupCode("owner@nodedc.local", agent.id); currentTime += 16 * 60_000; await assert.rejects(() => store.redeemSetupCode(setup.code, "Late device"), /setup_code_expired/); } finally { await rm(dataRoot, { recursive: true, force: true }); } });