feat: add system disclosure policy gate
Memind CI / Test, build, and release guards (pull_request) Successful in 3m14s
Memind CI / Test, build, and release guards (pull_request) Successful in 3m14s
This commit is contained in:
@@ -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 = [];
|
||||
|
||||
Reference in New Issue
Block a user