@@ -8,6 +8,11 @@ import {
88 storageServiceMockFns ,
99} from '@sim/testing'
1010import { beforeEach , describe , expect , it , vi } from 'vitest'
11+ import { hashDurableSecretProvenanceValue } from '@/lib/execution/durable-secret-provenance'
12+ import {
13+ bindKnowledgeDocumentFieldSecretProvenance ,
14+ createKnowledgeDocumentSourceValue ,
15+ } from '@/lib/knowledge/secret-provenance'
1116
1217const {
1318 mockIncrementStorageUsageInTx,
@@ -59,6 +64,34 @@ const sourceDoc = {
5964 mimeType : 'application/pdf' ,
6065}
6166
67+ function queueMappedDocumentCopy (
68+ source : Record < string , unknown > = sourceDoc ,
69+ provenanceRow : Record < string , unknown > = source
70+ ) : void {
71+ dbChainMockFns . limit
72+ . mockResolvedValueOnce ( [ ] )
73+ . mockResolvedValueOnce ( [ source ] )
74+ . mockResolvedValueOnce ( [ provenanceRow ] )
75+ . mockResolvedValueOnce ( [ ] )
76+ }
77+
78+ function mappedDocumentPlan ( ) : ForkContentPlan {
79+ return basePlan ( {
80+ documents : [
81+ {
82+ sourceDocId : 'doc-1' ,
83+ childDocId : 'child-doc-1' ,
84+ childKnowledgeBaseId : 'existing-target-kb' ,
85+ storageKey : 'kb/source-key' ,
86+ fileUrl : '/api/files/serve/kb%2Fsource-key' ,
87+ fileSize : 321 ,
88+ filename : 'report.pdf' ,
89+ mimeType : 'application/pdf' ,
90+ } ,
91+ ] ,
92+ } )
93+ }
94+
6295describe ( 'copyForkResourceContent' , ( ) => {
6396 beforeEach ( ( ) => {
6497 vi . clearAllMocks ( )
@@ -421,21 +454,10 @@ describe('copyForkResourceContent', () => {
421454 } )
422455
423456 it ( 'U-docs: fills a document copied into an existing target KB (blob re-key + placeholder update)' , async ( ) => {
457+ queueMappedDocumentCopy ( )
458+
424459 const result = await copyForkResourceContent ( {
425- contentPlan : basePlan ( {
426- documents : [
427- {
428- sourceDocId : 'doc-1' ,
429- childDocId : 'child-doc-1' ,
430- childKnowledgeBaseId : 'existing-target-kb' ,
431- storageKey : 'kb/source-key' ,
432- fileUrl : '/api/files/serve/kb%2Fsource-key' ,
433- fileSize : 321 ,
434- filename : 'report.pdf' ,
435- mimeType : 'application/pdf' ,
436- } ,
437- ] ,
438- } ) ,
460+ contentPlan : mappedDocumentPlan ( ) ,
439461 requestId : 'test' ,
440462 } )
441463
@@ -444,29 +466,130 @@ describe('copyForkResourceContent', () => {
444466 // The blob is re-keyed and the pre-created placeholder row's blob fields are updated.
445467 expect ( storageServiceMockFns . mockUploadFile ) . toHaveBeenCalledTimes ( 1 )
446468 expect ( dbChainMockFns . update ) . toHaveBeenCalledTimes ( 1 )
469+ expect ( dbChainMockFns . set ) . toHaveBeenCalledWith (
470+ expect . objectContaining ( { secretProvenanceVersion : null } )
471+ )
472+ expect ( dbChainMockFns . values ) . not . toHaveBeenCalledWith (
473+ expect . objectContaining ( { documentId : 'child-doc-1' } )
474+ )
475+ } )
476+
477+ it ( 'U-docs: rebinds tracked document provenance through the shared document copier' , async ( ) => {
478+ const source = {
479+ ...sourceDoc ,
480+ ...createKnowledgeDocumentSourceValue ( sourceDoc ) ,
481+ secretProvenanceVersion : 1 ,
482+ }
483+ const sourceValue = createKnowledgeDocumentSourceValue ( source )
484+ const provenance = bindKnowledgeDocumentFieldSecretProvenance (
485+ {
486+ status : 'exact' ,
487+ entries : [ { name : 'DOCUMENT_NAME' , encryptedValue : 'encrypted-name' } ] ,
488+ } ,
489+ 'filename' ,
490+ source . filename
491+ )
492+ queueMappedDocumentCopy ( source , {
493+ ...source ,
494+ provenanceSourceHash : hashDurableSecretProvenanceValue ( sourceValue ) ,
495+ status : 'exact' ,
496+ entries : provenance . status === 'exact' ? provenance . entries : [ ] ,
497+ } )
498+
499+ const result = await copyForkResourceContent ( {
500+ contentPlan : mappedDocumentPlan ( ) ,
501+ requestId : 'test' ,
502+ } )
503+
504+ expect ( result ) . toEqual ( { copied : 1 , failed : 0 , failures : [ ] } )
505+ expect ( dbChainMockFns . set ) . toHaveBeenCalledWith (
506+ expect . objectContaining ( { secretProvenanceVersion : 1 } )
507+ )
508+ expect ( dbChainMockFns . values ) . toHaveBeenCalledWith (
509+ expect . objectContaining ( {
510+ documentId : 'child-doc-1' ,
511+ status : 'exact' ,
512+ entries : [
513+ expect . objectContaining ( {
514+ name : 'DOCUMENT_NAME' ,
515+ encryptedValue : 'encrypted-name' ,
516+ sourceValueHash : expect . any ( String ) ,
517+ } ) ,
518+ ] ,
519+ } )
520+ )
521+ } )
522+
523+ it ( 'U-docs: keeps exact-empty provenance tracked instead of turning it into legacy state' , async ( ) => {
524+ const source = {
525+ ...sourceDoc ,
526+ ...createKnowledgeDocumentSourceValue ( sourceDoc ) ,
527+ secretProvenanceVersion : 1 ,
528+ }
529+ const sourceValue = createKnowledgeDocumentSourceValue ( source )
530+ queueMappedDocumentCopy ( source , {
531+ ...source ,
532+ provenanceSourceHash : hashDurableSecretProvenanceValue ( sourceValue ) ,
533+ status : 'exact' ,
534+ entries : [ ] ,
535+ } )
536+
537+ const result = await copyForkResourceContent ( {
538+ contentPlan : mappedDocumentPlan ( ) ,
539+ requestId : 'test' ,
540+ } )
541+
542+ expect ( result ) . toEqual ( { copied : 1 , failed : 0 , failures : [ ] } )
543+ expect ( dbChainMockFns . values ) . toHaveBeenCalledWith (
544+ expect . objectContaining ( {
545+ documentId : 'child-doc-1' ,
546+ status : 'exact' ,
547+ entries : [ ] ,
548+ } )
549+ )
550+ } )
551+
552+ it ( 'U-docs: preserves tracked unknown provenance instead of laundering it as legacy' , async ( ) => {
553+ const source = {
554+ ...sourceDoc ,
555+ ...createKnowledgeDocumentSourceValue ( sourceDoc ) ,
556+ secretProvenanceVersion : 1 ,
557+ }
558+ queueMappedDocumentCopy ( source , {
559+ ...source ,
560+ provenanceSourceHash : null ,
561+ status : null ,
562+ entries : null ,
563+ } )
564+
565+ const result = await copyForkResourceContent ( {
566+ contentPlan : mappedDocumentPlan ( ) ,
567+ requestId : 'test' ,
568+ } )
569+
570+ expect ( result ) . toEqual ( { copied : 1 , failed : 0 , failures : [ ] } )
571+ expect ( dbChainMockFns . set ) . toHaveBeenCalledWith (
572+ expect . objectContaining ( { secretProvenanceVersion : 1 } )
573+ )
574+ expect ( dbChainMockFns . values ) . toHaveBeenCalledWith (
575+ expect . objectContaining ( {
576+ documentId : 'child-doc-1' ,
577+ status : 'unknown' ,
578+ entries : [ ] ,
579+ } )
580+ )
447581 } )
448582
449583 it ( 'U-docs: a failed document fill is reported as a knowledge-document failure (for cleanup)' , async ( ) => {
584+ queueMappedDocumentCopy ( )
585+
450586 // The placeholder blob update throws; the doc fails on its own without touching its KB.
451587 dbChainMockFns . set . mockImplementationOnce ( ( ) => {
452588 throw new Error ( 'update failed' )
453589 } )
454590
455591 const result = await copyForkResourceContent ( {
456- contentPlan : basePlan ( {
457- documents : [
458- {
459- sourceDocId : 'doc-1' ,
460- childDocId : 'child-doc-1' ,
461- childKnowledgeBaseId : 'existing-target-kb' ,
462- storageKey : 'kb/source-key' ,
463- fileUrl : '/api/files/serve/kb%2Fsource-key' ,
464- fileSize : 321 ,
465- filename : 'report.pdf' ,
466- mimeType : 'application/pdf' ,
467- } ,
468- ] ,
469- } ) ,
592+ contentPlan : mappedDocumentPlan ( ) ,
470593 requestId : 'test' ,
471594 } )
472595
@@ -476,23 +599,11 @@ describe('copyForkResourceContent', () => {
476599 } )
477600
478601 it ( 'U-docs: refuses to charge when the target knowledge base moved workspaces' , async ( ) => {
602+ queueMappedDocumentCopy ( )
479603 dbChainMockFns . for . mockResolvedValueOnce ( [ { workspaceId : 'other-workspace' } ] )
480604
481605 const result = await copyForkResourceContent ( {
482- contentPlan : basePlan ( {
483- documents : [
484- {
485- sourceDocId : 'doc-1' ,
486- childDocId : 'child-doc-1' ,
487- childKnowledgeBaseId : 'existing-target-kb' ,
488- storageKey : 'kb/source-key' ,
489- fileUrl : '/api/files/serve/kb%2Fsource-key' ,
490- fileSize : 321 ,
491- filename : 'report.pdf' ,
492- mimeType : 'application/pdf' ,
493- } ,
494- ] ,
495- } ) ,
606+ contentPlan : mappedDocumentPlan ( ) ,
496607 requestId : 'test' ,
497608 } )
498609
0 commit comments