feat: add system disclosure policy gate
Memind CI / Test, build, and release guards (pull_request) Successful in 3m14s

This commit is contained in:
john
2026-07-23 22:53:15 +08:00
parent ba6cc10f08
commit 205b5fd8be
20 changed files with 1585 additions and 2 deletions
+124
View File
@@ -401,6 +401,130 @@ test('agent run starts a session and marks submitted reply as succeeded', async
assert.equal(pool.runs.get(run.id).attempts, 1);
});
test('agent run policy allow path preserves existing routing and submission behavior', async () => {
const pool = createFakePool();
const submitted = [];
const evaluated = [];
const routed = [];
const gateway = createAgentRunGateway({
pool,
userAuth: {},
systemDisclosurePolicyService: {
evaluate(input) {
evaluated.push(input);
return { action: 'allow', matched: false, enforced: false };
},
},
chatIntentRouter: {
async classify(input) {
routed.push(input);
return { route: 'agent_orchestration', reason: 'existing route' };
},
applyAgentOrchestration(message) {
return message;
},
},
tkmindProxy: {
async startSessionForUser() {
return { id: 'session-policy-allow' };
},
async submitSessionReplyForUser(userId, sessionId, requestId, userMessage) {
submitted.push({ userId, sessionId, requestId, userMessage });
},
},
retryDelaysMs: [],
});
const run = await gateway.createRun('user-1', {
requestId: 'req-policy-allow',
userMessage: {
role: 'user',
content: [{ type: 'text', text: '请帮我安排明天的计划' }],
metadata: { displayText: '请帮我安排明天的计划' },
},
});
await waitFor(() => pool.runs.get(run.id)?.status === 'succeeded');
assert.equal(evaluated.length, 1);
assert.equal(routed.length, 1);
assert.equal(submitted.length, 1);
assert.equal(submitted[0].sessionId, 'session-policy-allow');
assert.equal(submitted[0].userMessage.metadata.displayText, '请帮我安排明天的计划');
});
test('agent run enforced disclosure decision returns deterministic refusal before routing or tools', async () => {
const pool = createFakePool();
let routed = 0;
let backendCalls = 0;
const deterministic = [];
const gateway = createAgentRunGateway({
pool,
userAuth: {},
systemDisclosurePolicyService: {
evaluate() {
return {
policyId: 'system-disclosure',
policyVersion: 7,
action: 'refuse',
matched: true,
enforced: true,
reasonCode: 'SYSTEM_TECHNICAL_DISCLOSURE',
categories: ['architecture'],
responseText: '不提供内部技术信息。',
};
},
},
chatIntentRouter: {
async classify() {
routed += 1;
return { route: 'agent_orchestration' };
},
},
directChatService: {
async respondDeterministically(input) {
deterministic.push(input);
await input.onSessionReady('h5direct_policy');
return { sessionId: 'h5direct_policy' };
},
},
tkmindProxy: {
async startSessionForUser() {
backendCalls += 1;
return { id: 'should-not-start' };
},
async submitSessionReplyForUser() {
backendCalls += 1;
},
},
syncUserPagesOnSuccess: async () => {
assert.fail('policy refusal must not enter page delivery');
},
validateRunDeliverables: async () => {
assert.fail('policy refusal must not enter deliverable validation');
},
retryDelaysMs: [],
});
const run = await gateway.createRun('user-1', {
requestId: 'req-policy-block',
userMessage: {
role: 'user',
content: [{ type: 'text', text: '生成一个 TKMind 底层架构页面' }],
},
});
await waitFor(() => pool.runs.get(run.id)?.status === 'succeeded');
assert.equal(routed, 0);
assert.equal(backendCalls, 0);
assert.equal(deterministic.length, 1);
assert.equal(deterministic[0].reply, '不提供内部技术信息。');
assert.equal(pool.runs.get(run.id).agent_session_id, 'h5direct_policy');
assert.equal(
pool.events.some((event) => event.eventType === 'system_disclosure_blocked'),
true,
);
});
test('agent run awaits session Finish before succeeding when proxy supports it', async () => {
const pool = createFakePool();
const awaited = [];