@@ -159,7 +159,7 @@ describe('maybeWriteOutputToFile', () => {
159159 expect ( mockWriteWorkspaceFileByPath ) . not . toHaveBeenCalled ( )
160160 } )
161161
162- it ( 'does not deny a read -only principal when no workspace write occurs (sandbox export active) ' , async ( ) => {
162+ it ( 'passes through sandbox -only receipts without attempting another workspace write' , async ( ) => {
163163 const exportedResult = {
164164 success : true ,
165165 output : {
@@ -175,7 +175,13 @@ describe('maybeWriteOutputToFile', () => {
175175
176176 const result = await maybeWriteOutputToFile (
177177 RunFunction . id ,
178- { outputs : { files : [ { path : 'files/report.csv' , mode : 'overwrite' } ] } } ,
178+ {
179+ outputs : {
180+ files : [
181+ { path : 'files/report.csv' , mode : 'overwrite' , sandboxPath : '/home/user/report.csv' } ,
182+ ] ,
183+ } ,
184+ } ,
179185 exportedResult ,
180186 buildContext ( { userPermission : 'read' } )
181187 )
@@ -188,18 +194,55 @@ describe('maybeWriteOutputToFile', () => {
188194 const result = await maybeWriteOutputToFile (
189195 RunFunction . id ,
190196 { outputs : { files : [ { path : 'files/report.csv' , mode : 'overwrite' } ] } } ,
191- { success : true , output : { result : 'name,age\nAlice,30' , stdout : '' } } ,
197+ { success : true , output : { result : 'name,age\nAlice,30' , stdout : 'Exported 1 row ' } } ,
192198 buildContext ( )
193199 )
194200
195201 expect ( result . success ) . toBe ( true )
202+ expect ( result . output ) . toMatchObject ( { stdout : 'Exported 1 row' } )
196203 expect ( mockWriteWorkspaceFileByPath ) . toHaveBeenCalledTimes ( 1 )
197204 expect ( mockWriteWorkspaceFileByPath ) . toHaveBeenCalledWith (
198205 expect . anything ( ) ,
199206 expect . objectContaining ( { secretProvenance : { status : 'exact' , entries : [ ] } } )
200207 )
201208 } )
202209
210+ it ( 'writes returned data alongside a completed sandbox export and keeps both receipts' , async ( ) => {
211+ const existingFile = { fileId : 'raw-file' , fileName : 'raw.csv' , vfsPath : 'files/raw.csv' }
212+ const existingResource = {
213+ type : 'file' as const ,
214+ id : 'raw-file' ,
215+ title : 'raw.csv' ,
216+ path : 'files/raw.csv' ,
217+ }
218+ const result = await maybeWriteOutputToFile (
219+ RunFunction . id ,
220+ {
221+ outputs : {
222+ files : [
223+ { path : 'files/raw.csv' , sandboxPath : '/home/user/raw.csv' } ,
224+ { path : 'files/report.csv' } ,
225+ ] ,
226+ } ,
227+ } ,
228+ {
229+ success : true ,
230+ output : { result : [ { name : 'Ada' } ] , stdout : '1 row' , exported : { files : [ existingFile ] } } ,
231+ resources : [ existingResource ] ,
232+ } ,
233+ buildContext ( )
234+ )
235+
236+ expect ( mockWriteWorkspaceFileByPath ) . toHaveBeenCalledTimes ( 1 )
237+ expect ( mockWriteWorkspaceFileByPath . mock . calls [ 0 ] ?. [ 1 ] . buffer . toString ( ) ) . toBe ( 'name\nAda' )
238+ expect ( result . output ) . toMatchObject ( {
239+ result : [ { name : 'Ada' } ] ,
240+ stdout : '1 row' ,
241+ files : [ existingFile , expect . objectContaining ( { vfsPath : 'files/report.csv' } ) ] ,
242+ } )
243+ expect ( result . resources ) . toContainEqual ( existingResource )
244+ } )
245+
203246 it ( 'classifies large structured output from its serialized bytes instead of its object count' , async ( ) => {
204247 const registry = new ResolvedSecretTraceRegistry (
205248 [
0 commit comments