返回 CodeWhale
review-adapters.test.mjs
根目录 / crates / tui / extension-host / test / review-adapters.test.mjs
1 import test from 'node:test'
2 import assert from 'node:assert/strict'
3 import { dirname, join } from 'node:path'
4 import { readFileSync } from 'node:fs'
5 import { createHash } from 'node:crypto'
6 import { transformStockSnapshot } from '../dist/stock-adapters.mjs'
7 import { createHarnessModule } from '../dist/builtin/harness.mjs'
8 import { startHost, BUNDLE } from './harness.mjs'
9 const LIMIT=16*1024*1024
10 const fixture=JSON.parse(readFileSync(new URL('../../tests/fixtures/review-host-parity.json',import.meta.url),'utf8'))
11 const snapshot=(operation,input)=>({kind:'stock_adapter',operation,input})
12 const transform=(operation,input)=>transformStockSnapshot(snapshot(operation,input))
13 const owner={plugin_id:'host:harness',generation:4,owner_token:'fixture-exact-review-job'}
14 const params=id=>({owner,execution_id:id,ticket:'opaque-core-execution-grant',deadline_ms:10000})
15 const part={number:1,diff_fingerprint:'sha256:'+'a'.repeat(64),diff_chars:42,file_count:1,files:['a/x b/x']}
16 const manifest={base_sha:'b'.repeat(40),head_sha:'a'.repeat(40),diff_fingerprint:'sha256:'+'c'.repeat(64),diff_chars:42,file_count:1,binary_file_patches:0,binary_contents_semantically_inspected:false,max_chars_per_pass:40000,passes:[part],skipped_files:[]}
17 const passInput=()=>({number:7,view:{title:'untrusted title',body:'untrusted body'},manifest,pass:part,diff:'diff --git a/x b/x\n+END\n',context:{files:[{path:'x',source:'漢字e\u0301',head_sha:manifest.head_sha}],limit:64},sort_keys:true})
18 const sorted=value=>Array.isArray(value)?value.map(sorted):value&&typeof value==='object'?Object.fromEntries(Object.entries(value).sort(([a],[b])=>a<b?-1:a>b?1:0).map(([key,value])=>[key,sorted(value)])):value
19 const envelopeBytes=value=>8+Buffer.byteLength(`{"jsonrpc":"2.0","id":18446744073709551615,"result":${JSON.stringify(value)}}`)
20
21 test('frozen Core formatter counterpart matches all sixteen source interactive and local/posted report cases',()=>{
22 for(const {operation,input,content} of fixture.cases) assert.equal(transform(operation,input).result.content,content)
23 })
24 test('file numbering uses scalar source lines, CRLF and terminal lone CR without truncation',()=>{
25 const content=Array.from({length:10001},(_,i)=>i===10000?'漢字🐋e\u0301END':'x').join('\r\n')+'\r'
26 const output=transform('review_source_prompt',{kind:'file',display:'x',content}).result.content
27 assert.ok(output.includes('10000 | x\n10001 | 漢字🐋e\u0301END\r\n\nEnd of file.'))
28 assert.ok(!output.includes('...'))
29 })
30 test('complete pass preserves exact Core manifest, source provenance and serialized map order',()=>{
31 const input=passInput(), content=transform('review_pass_prompt',input).result.content,parsed=JSON.parse(content)
32 assert.deepEqual(parsed.manifest,input.manifest);assert.deepEqual(parsed.pass,input.pass);assert.deepEqual(parsed.repository_context,input.context)
33 assert.deepEqual(parsed.pull_request,{number:7,title:input.view.title,description:input.view.body});assert.equal(parsed.diff,input.diff)
34 assert.equal(parsed.untrusted_repository_data,true);assert.ok(parsed.task.includes('No build or tests have been run.'))
35 assert.equal(content,JSON.stringify(sorted(parsed)))
36 input.sort_keys=false;const preserved=transform('review_pass_prompt',input).result.content
37 assert.ok(preserved.startsWith('{"task":'));assert.deepEqual(JSON.parse(preserved),parsed)
38 })
39 test('partial pass explicitly carries every unread file and never invents full coverage',()=>{
40 const input=passInput();input.manifest={...manifest,skipped_files:[{file:'a/unread b/unread',chars:30000,reason:'beyond the max_passes budget'}]};input.context=null
41 const parsed=JSON.parse(transform('review_pass_prompt',input).result.content)
42 assert.ok(parsed.task.includes('partial review (pass 1 of 1)'));assert.ok(parsed.task.includes('a/unread b/unread (30000 chars; beyond the max_passes budget)'));assert.ok(parsed.task.includes('Do not claim full coverage.'))
43 assert.equal(parsed.repository_context,null);assert.deepEqual(parsed.manifest,input.manifest)
44 })
45 test('complete captured review larger than one MiB is accepted with the final patch intact',()=>{
46 const diff='漢'.repeat(400000)+'FINAL_PATCH_END',input={kind:'cli_diff',diff}
47 assert.ok(Buffer.byteLength(JSON.stringify(snapshot('review_source_prompt',input)))>1024*1024)
48 const result=transform('review_source_prompt',input).result
49 assert.ok(result.content.endsWith('FINAL_PATCH_END\n\nEnd of diff.'));assert.equal(result.success,true);assert.equal(result.metadata,null)
50 })
51 test('serialized review snapshot over its purpose cap refuses even when raw source fits',()=>{
52 const input={kind:'cli_diff',diff:'\0'.repeat(3*1024*1024)}
53 assert.ok(Buffer.byteLength(input.diff)<LIMIT);assert.ok(envelopeBytes(snapshot('review_source_prompt',input))>LIMIT)
54 assert.throws(()=>transform('review_source_prompt',input),/review.*16 MiB/)
55 })
56 test('nested prompt result escaping is separately bounded without dropping context',()=>{
57 const input=passInput();input.context={source:'\0'.repeat(2500000)}
58 assert.ok(envelopeBytes(snapshot('review_pass_prompt',input))<LIMIT)
59 assert.throws(()=>transform('review_pass_prompt',input),/review result exceeds 16 MiB/)
60 })
61 test('other helpers retain one MiB and unknown review operations never obtain a larger allowance',()=>{
62 for(const operation of ['speech_options','review_publish']) assert.throws(()=>transform(operation,{payload:'x'.repeat(1024*1024+1)}),/1 MiB/)
63 for(const [operation,input] of [['review_source_prompt',{kind:'url',url:'https://example.invalid'}],['review_pass_prompt',{...passInput(),sort_keys:null}],['review_pass_prompt',{...passInput(),context:undefined}],['review_report',{review:[],output:'',posted:false}],['review_interactive_pr',{number:2**53,view:{},diff:''}]]) assert.throws(()=>transform(operation,input))
64 })
65 test('raw prose is returned byte-exact and presenter cannot grant metadata or approval',()=>{
66 const input={review:null,output:'\0raw ```suggestion\nunknown\n```\n',posted:true},result=transform('review_report',input).result
67 assert.equal(result.content,input.output);assert.equal(result.metadata,null);assert.equal(result.success,true)
68 })
69 test('actual module redeems one opaque grant for every closed review operation',async()=>{
70 const cases=[fixture.cases[0],{operation:'review_pass_prompt',input:passInput()},fixture.cases.find(x=>x.operation==='review_interactive_pr'),fixture.cases.find(x=>x.operation==='review_report')]
71 for(const [i,entry] of cases.entries()) {
72 const calls=[],runner=createHarnessModule({async request(method,args){calls.push([method,args]);return snapshot(entry.operation,entry.input)}},owner)
73 assert.deepEqual(await runner.run(params(`case${i}`),new AbortController().signal),transform(entry.operation,entry.input))
74 assert.deepEqual(calls,[['exec/redeem',{owner,execution_id:`case${i}`,ticket:'opaque-core-execution-grant'}]]);await runner.dispose()
75 }
76 })
77 test('cancellation and disposed owner suppress late review completion',async()=>{
78 let finish;const runner=createHarnessModule({request(){return new Promise(resolve=>{finish=resolve})}},owner),controller=new AbortController()
79 const pending=runner.run(params('cancel'),controller.signal);controller.abort();await assert.rejects(pending,/cancelled/)
80 finish(snapshot('review_source_prompt',{kind:'cli_diff',diff:'late'}));await runner.dispose()
81 await assert.rejects(runner.run(params('disposed'),new AbortController().signal),/stale/)
82 })
83 test('real builtin Host process presents all four adopted review operations over existing wire',async t=>{
84 const host=await startHost({tier:'builtin'});t.after(()=>host.stop())
85 const entry=join(dirname(BUNDLE),'builtin','harness.mjs'),sha256=createHash('sha256').update(readFileSync(entry)).digest('hex')
86 assert.equal((await host.call('ext/activate',{owner,plugin_name:'Pinned review presenter',entry:{path:entry,sha256},config:{}})).status,'ok')
87 const cases=[fixture.cases[0],{operation:'review_pass_prompt',input:passInput()},fixture.cases.find(x=>x.operation==='review_interactive_pr'),fixture.cases.find(x=>x.operation==='review_report'),{operation:'review_source_prompt',input:{kind:'cli_diff',diff:'漢'.repeat(400000)+'WIRE_END'}}]
88 for(const [i,row] of cases.entries()) {
89 const redeemed=host.waitFor(message=>message.method==='exec/redeem'),result=host.call('harness/run',params(`wire${i}`)),request=await redeemed
90 assert.deepEqual(request.params,{owner,execution_id:`wire${i}`,ticket:'opaque-core-execution-grant'})
91 host.send({jsonrpc:'2.0',id:request.id,result:snapshot(row.operation,row.input)})
92 assert.deepEqual(await result,transform(row.operation,row.input))
93 }
94 assert.deepEqual(await host.call('ext/deactivate',{owner}),{disposed:true,leaked:[]})
95 })
96 test('real Host refuses encoded purpose overflow then remains usable without retrying the grant',async t=>{
97 const host=await startHost({tier:'builtin'});t.after(()=>host.stop())
98 const entry=join(dirname(BUNDLE),'builtin','harness.mjs'),sha256=createHash('sha256').update(readFileSync(entry)).digest('hex')
99 assert.equal((await host.call('ext/activate',{owner,plugin_name:'Bounded review presenter',entry:{path:entry,sha256},config:{}})).status,'ok')
100 for(const [i,diff] of ['\0'.repeat(3*1024*1024),'accepted_after_refusal'].entries()) {
101 const redeemed=host.waitFor(message=>message.method==='exec/redeem'),result=host.call('harness/run',params(`bounded${i}`)),request=await redeemed
102 host.send({jsonrpc:'2.0',id:request.id,result:snapshot('review_source_prompt',{kind:'cli_diff',diff})})
103 if(i===0) await assert.rejects(result,/review.*16 MiB/)
104 else assert.ok((await result).result.content.includes(diff))
105 }
106 assert.equal(host.coreCalls.length,0);assert.deepEqual(await host.call('ext/deactivate',{owner}),{disposed:true,leaked:[]})
107 })
108
108 lines Plain Text