@@ -12,14 +12,15 @@ import {
1212 knowledgeBase ,
1313 organization ,
1414 outboxEvent ,
15+ permissions ,
1516 user ,
1617 workspace ,
1718 workspaceFiles ,
1819} from '@sim/db/schema'
1920import { deleteWorkspaceFixture } from '@sim/db/testing/workspace-fixtures'
2021import { remoteSandboxMock , remoteSandboxMockFns } from '@sim/testing/mocks/remote-sandbox.mock'
2122import { generateId } from '@sim/utils/id'
22- import { eq , inArray , sql } from 'drizzle-orm'
23+ import { and , eq , inArray , sql } from 'drizzle-orm'
2324import JSZip from 'jszip'
2425import { afterAll , beforeAll , describe , expect , it , vi } from 'vitest'
2526
@@ -64,7 +65,10 @@ vi.mock('@/lib/embeddings', async () => ({
6465} ) )
6566
6667import { functionExecuteBodySchema } from '@/lib/api/contracts'
67- import { fileManageDecompressBodySchema } from '@/lib/api/contracts/tools/file'
68+ import {
69+ fileManageBodySchema ,
70+ fileManageDecompressBodySchema ,
71+ } from '@/lib/api/contracts/tools/file'
6872import { observeContentDelivery } from '@/lib/core/application'
6973import { processOutboxEventById } from '@/lib/core/outbox/service'
7074import { decryptSecret , encryptSecret } from '@/lib/core/security/encryption'
@@ -990,9 +994,121 @@ describe('execution archive durable provenance', () => {
990994 expect ( await isOpaqueWorkspaceFileEgressSafe ( ids . workspaceId , source . identity ) ) . toBe ( true )
991995 } )
992996
993- it . each ( [ false , true ] ) (
994- 'refuses tracked unknown execution attachments with historical metadata (archivedOnly=%s)' ,
995- async ( archivedOnly ) => {
997+ it . each ( [ 'append' , 'write' ] as const ) (
998+ 'preserves encrypted origins when another member performs %s' ,
999+ async ( operation ) => {
1000+ const ids = await seed ( )
1001+ await db
1002+ . update ( permissions )
1003+ . set ( { permissionType : 'write' } )
1004+ . where ( and ( eq ( permissions . userId , ids . bobId ) , eq ( permissions . entityId , ids . workspaceId ) ) )
1005+ const priorSecret = 'fixture-prior-origin-secret'
1006+ const previous = {
1007+ status : 'exact' as const ,
1008+ entries : [
1009+ {
1010+ encryptedValue : ( await encryptSecret ( priorSecret ) ) . encrypted ,
1011+ sourceUserId : ids . aliceId ,
1012+ sourceWorkspaceId : ids . workspaceId ,
1013+ name : 'PRIOR_TOKEN' ,
1014+ } ,
1015+ ] ,
1016+ }
1017+ const source = await uploadWorkspaceFile (
1018+ ids . workspaceId ,
1019+ ids . aliceId ,
1020+ Buffer . from ( priorSecret ) ,
1021+ `${ generateId ( ) } .txt` ,
1022+ 'text/plain' ,
1023+ { secretProvenance : previous , notifyWorkspaceChange : false }
1024+ )
1025+ const response = await executeFileManageOperation (
1026+ fileManageBodySchema . parse ( {
1027+ operation,
1028+ workspaceId : ids . workspaceId ,
1029+ fileName : source . name ,
1030+ content : FIXTURE_SECRET ,
1031+ ...( operation === 'write' ? { overwrite : true } : { } ) ,
1032+ [ PRIVATE_SECRET_PROVENANCE_FIELD ] : {
1033+ version : 1 ,
1034+ complete : true ,
1035+ selections : [
1036+ {
1037+ key : 'content' ,
1038+ provenance : {
1039+ version : 1 ,
1040+ complete : true ,
1041+ scope : { userId : ids . bobId , workspaceId : ids . workspaceId } ,
1042+ entries : [
1043+ {
1044+ name : 'NEW_TOKEN' ,
1045+ encryptedValue : ( await encryptSecret ( FIXTURE_SECRET ) ) . encrypted ,
1046+ } ,
1047+ ] ,
1048+ } ,
1049+ } ,
1050+ ] ,
1051+ } ,
1052+ } ) ,
1053+ {
1054+ principal : createWorkspaceFileDelegatedPrincipal ( {
1055+ serviceId : 'executor' ,
1056+ subjectUserId : ids . bobId ,
1057+ workspaceId : ids . workspaceId ,
1058+ delegationId : generateId ( ) ,
1059+ executionId : ids . executionId ,
1060+ } ) ,
1061+ workspaceId : ids . workspaceId ,
1062+ attributedUserId : ids . bobId ,
1063+ fileAccessUserId : ids . bobId ,
1064+ workflowId : ids . workflowId ,
1065+ executionId : ids . executionId ,
1066+ headers : new Headers ( {
1067+ [ PRIVATE_SECRET_PROVENANCE_HEADER ] : PRIVATE_SECRET_PROVENANCE_BUNDLE_V1 ,
1068+ } ) ,
1069+ requestId : generateId ( ) ,
1070+ }
1071+ )
1072+ expect ( response . status , await response . text ( ) ) . toBe ( 200 )
1073+ const record = await getWorkspaceFile ( ids . workspaceId , source . id )
1074+ if ( ! record ) throw new Error ( 'Edited file disappeared' )
1075+ const bytes = await downloadFile ( { key : record . key , context : 'workspace' } )
1076+ expect ( bytes . toString ( ) ) . toBe (
1077+ operation === 'append' ? priorSecret + FIXTURE_SECRET : FIXTURE_SECRET
1078+ )
1079+ const registry = new ResolvedSecretTraceRegistry ( [ ] , {
1080+ userId : ids . bobId ,
1081+ workspaceId : ids . workspaceId ,
1082+ } )
1083+ expect (
1084+ await importWorkspaceFileSecretProvenanceForRuntime ( {
1085+ workspaceId : ids . workspaceId ,
1086+ identity : {
1087+ fileId : record . id ,
1088+ key : record . key ,
1089+ context : 'workspace' ,
1090+ contentUpdatedAt : record . contentUpdatedAt ?? undefined ,
1091+ } ,
1092+ registry,
1093+ } )
1094+ ) . toBe ( true )
1095+ const shown = projectResolvedSecretModelContent ( bytes . toString ( ) , registry )
1096+ expect ( shown . safe ) . toBe ( true )
1097+ expect ( JSON . stringify ( shown ) ) . not . toContain ( FIXTURE_SECRET )
1098+ expect ( JSON . stringify ( shown ) ) . not . toContain ( priorSecret )
1099+ expect ( JSON . stringify ( shown ) ) . toContain ( '{{NEW_TOKEN}}' )
1100+ if ( operation === 'append' ) expect ( JSON . stringify ( shown ) ) . toContain ( '[REDACTED_SECRET]' )
1101+ }
1102+ )
1103+
1104+ it . each ( [
1105+ [ 'execution' , false ] ,
1106+ [ 'execution' , true ] ,
1107+ [ 'workspace' , true ] ,
1108+ [ 'mothership' , true ] ,
1109+ ] as const ) (
1110+ 'retains refusal evidence for %s attachments (archivedOnly=%s)' ,
1111+ async ( context , archivedOnly ) => {
9961112 const ids = await seed ( )
9971113 const file = await uploadExecutionFile (
9981114 ids ,
@@ -1005,7 +1121,7 @@ describe('execution archive durable provenance', () => {
10051121 if ( archivedOnly ) {
10061122 await db
10071123 . update ( workspaceFiles )
1008- . set ( { deletedAt : new Date ( ) } )
1124+ . set ( { deletedAt : new Date ( ) , context } )
10091125 . where ( eq ( workspaceFiles . key , file . key ) )
10101126 } else {
10111127 await db . insert ( workspaceFiles ) . values ( {
0 commit comments