diff --git a/src/__tests__/profile-injection.test.ts b/src/__tests__/profile-injection.test.ts index bf2f50c..3e297bf 100644 --- a/src/__tests__/profile-injection.test.ts +++ b/src/__tests__/profile-injection.test.ts @@ -110,6 +110,42 @@ test("fail-closed: accountId null → base pura, loadFacts NÃO chamado", async assert.equal(out, FRIEND_INSTRUCTIONS); }); +// --- curinga "*": todas as contas, mas ainda fail-closed em accountId ausente - +test('curinga "*": qualquer accountId presente injeta os PRÓPRIOS fatos', async () => { + const spyA = spyLoad(); + const a = await resolveInstructions({ + owner: false, + injectEnabled: true, + accountId: "acct_qualquer", + allowlist: ["*"], + loadFacts: spyA.fn, + }); + assert.ok(a.includes("FATO_DA_CONTA_acct_qualquer"), "* injeta os fatos da conta"); + assert.deepEqual(spyA.calls(), ["acct_qualquer"], "carregou só a própria conta"); +}); + +test('curinga "*": accountId null/ausente → base pura (fail-closed mesmo com *)', async () => { + const out = await resolveInstructions({ + owner: false, + injectEnabled: true, + accountId: null, + allowlist: ["*"], + loadFacts: neverCalled(), + }); + assert.equal(out, FRIEND_INSTRUCTIONS, "* não burla o fail-closed de accountId ausente"); +}); + +test('curinga "*": flag off → base pura (não injeta)', async () => { + const out = await resolveInstructions({ + owner: false, + injectEnabled: false, + accountId: "acct_qualquer", + allowlist: ["*"], + loadFacts: neverCalled(), + }); + assert.equal(out, FRIEND_INSTRUCTIONS); +}); + test("fail-closed: accountId '' (vazio) → base pura, loadFacts NÃO chamado", async () => { const out = await resolveInstructions({ owner: true, diff --git a/src/mcp-account-config.ts b/src/mcp-account-config.ts index 17b3547..b33996b 100644 --- a/src/mcp-account-config.ts +++ b/src/mcp-account-config.ts @@ -95,10 +95,13 @@ export async function resolveInstructions(args: { const render = args.render ?? renderProfile; const budget = args.budget ?? PROFILE_CHAR_BUDGET; - // FAIL-CLOSED: injeta só com flag ligada, accountId presente E na allowlist. - // accountId vazio/ausente ou fora do allowlist ⇒ nunca toca loadFacts. + // FAIL-CLOSED: injeta só com flag ligada, accountId presente E (allowlist com o + // curinga "*" = todas as contas, OU a conta explicitamente na allowlist). + // accountId vazio/ausente ⇒ nunca toca loadFacts, mesmo com "*" (fail-closed). const allowed = - args.injectEnabled && !!args.accountId && args.allowlist.includes(args.accountId); + args.injectEnabled && + !!args.accountId && + (args.allowlist.includes("*") || args.allowlist.includes(args.accountId)); // ISOLAMENTO: cada conta carrega SÓ os próprios fatos (loadFacts(accountId)). const profileBlock = allowed