import test from 'node:test'; import assert from 'node:assert/strict'; import path from 'node:path'; import {runAccountBinding} from '../skills/ksf-workshop-runtime/scripts/ksf-account.mjs'; import {parseArgs} from '../skills/ksf-workshop-runtime/scripts/ksf-secure.mjs'; import {redactIdentity} from '../skills/ksf-workshop-runtime/scripts/ksf-identity.mjs'; import {runWorkshop} from '../skills/ksf-workshop-runtime/scripts/ksf-workshop.mjs'; const profile={key:'participant-registration:1ab680ff-4ad4-4377-9333-3b2f23e26bb7',account:{platform:'fmode',accountName:'guopeng',accountId:null}}; const task={participant:{profileKey:profile.key},username:'guopeng',displayName:'果鹏'}; const opts={requestId:'first-link',agentProfile:{role:'workshop'},participantProfile:profile}; test('首次绑定命令只传当前档案和自报称呼账号,不收密码或冒充平台确认',async()=>{ let called=0;const call=async(name,p)=>{called++;assert.equal(name,'ksfWorkshopAccount');assert.equal(p.action,'prepare');assert.equal(p.participantProfileKey,profile.key);assert.ok(!('password'in p));return{status:'awaiting_account_confirmation'};}; const r=await runAccountBinding('account-prepare',task,{...opts,call});assert.equal(r.status,'awaiting_account_confirmation');assert.equal(called,1); await assert.rejects(()=>runAccountBinding('account-confirm',task,{...opts,call}),{code:'INVALID_INPUT'});assert.equal(called,1); }); test('档案不匹配、冒用其他账号或通道字段写入前拒绝',async()=>{ const call=()=>{assert.fail('must stop before network');}; for(const t of [{...task,username:'liuna'},{...task,participant:{profileKey:'another'}},{...task,password:'forbidden'}])await assert.rejects(()=>runAccountBinding('account-prepare',t,{...opts,call})); const status=await runAccountBinding('account-status',{participant:task.participant},{...opts,call:async()=>({status:'bound',memberKey:'verified-key'})});assert.equal(status.memberKey,'verified-key'); }); test('新增受控命令沿用加密凭据入口,要求Agent及请求编号',()=>{ const flags=['--input',path.resolve('work/task.json'),'--request-id','link-test','--agent-profile','agent-account:'+'a'.repeat(64)]; assert.equal(parseArgs(['account-prepare',...flags]).command,'account-prepare'); assert.equal(parseArgs(['account-status',...flags]).command,'account-status'); assert.throws(()=>parseArgs(['account-prepare','--input',path.resolve('work/task.json'),'--request-id','link-test']),{code:'AGENT_PROFILE_REQUIRED'}); }); test('报告回读移除新增私有绑定快照和平台编号,只保留公开memberKey',()=>{ const result=redactIdentity({memberKey:'public-member',meta:{attribution:{participantKey:'old-participant',accountBinding:{platformUserId:'private-user'},accountProfileKey:'private-profile',platformUserId:'private-user'}}}); assert.deepEqual(result,{memberKey:'public-member',meta:{attribution:{participantKey:'old-participant'}}}); }); const bindingContract={schema:'ksf.workshop-account-binding.v1',enabled:true,requiredFor:['fmode'],function:'ksfWorkshopAccount',firstUse:'confirm-display-name-and-account',proof:'platform-session',canonicalMember:'platform-account',oneMemberPerAccount:true,unboundSubmission:'reject',historicalAttributionPreserved:true}; test('真实workshop-contract路径保留公开账号绑定契约,不把正常脱敏当成服务端未部署',async()=>{ const contract={workshop:{version:'ksf.workshop.v1',accountBinding:bindingContract}}; const result=await runWorkshop('workshop-contract',{}, {requestId:'contract-regression',call:async(name)=>{assert.equal(name,'ksfGetIngestContract');return structuredClone(contract);}}); assert.deepEqual(result.workshop.accountBinding,bindingContract); }); test('会话创建回执保留安全绑定摘要,私有归属快照即使伪装成公开契约仍不透出',()=>{ const summary={schema:'ksf.workshop-account-binding.v1',status:'bound',memberKey:'platform-account:'+'a'.repeat(64),username:'guopeng',displayName:'果鹏',companyId:'FKieRbIoGt',verifiedAt:'2026-11-12T06:00:00.000Z',source:'platform_session'}; const input={sessionId:'session-one',accountBinding:{...summary,platformUserId:'private-user'},record:{meta:{attribution:{accountBinding:{...bindingContract,platformUserId:'private-user'},accountProfileKey:'private-profile'}}}}; const result=redactIdentity(input); assert.deepEqual(result.accountBinding,summary);assert.equal(result.record.meta.attribution.accountBinding,undefined); assert.ok(!JSON.stringify(result).includes('private-user'));assert.ok(!JSON.stringify(result).includes('private-profile')); });