33 */
44import { createMockRequest } from '@sim/testing'
55import { describe , expect , it } from 'vitest'
6- import { AuthType } from '@/lib/auth/hybrid'
76import {
87 PRIVATE_SECRET_PROVENANCE_BUNDLE_V1 ,
98 PRIVATE_SECRET_PROVENANCE_FIELD ,
@@ -13,29 +12,16 @@ import {
1312 RESOLVED_SECRET_PROVENANCE_METADATA_V1 ,
1413} from '@/lib/execution/private-tool-metadata'
1514import { TableRowProvenanceError } from '@/lib/table/application/row-secret-provenance'
16- import { rowDataNameToId } from '@/lib/table/column-keys'
1715import { tableRowSecretProvenanceSelectionKey } from '@/lib/table/secret-provenance-selection'
18- import type { RowData } from '@/lib/table/types'
1916import {
20- createTableWriteProvenanceTargets ,
2117 finalizeTableRowsProvenance ,
2218 negotiateTableRowsProvenance ,
2319 readTableRowProvenanceEnvelope ,
24- resolveTableWriteSecretProvenance ,
2520} from '@/app/api/table/row-secret-provenance'
2621
2722const USER_ID = 'user-1'
2823const WORKSPACE_ID = 'ws-1'
2924
30- /** Mirrors the internal-JWT wire translator: names → ids, unknown names dropped. */
31- const ID_BY_NAME = new Map ( [
32- [ 'email' , 'col_email' ] ,
33- [ 'company' , 'col_company' ] ,
34- ] )
35-
36- const translateNames = ( data : RowData ) : RowData => rowDataNameToId ( data , ID_BY_NAME )
37- const translateIdentity = ( data : RowData ) : RowData => data
38-
3925function traceProvenance ( ) {
4026 return {
4127 version : 1 ,
@@ -59,221 +45,6 @@ function bundleRequest(selectionKeys: string[]) {
5945 return { request, payload }
6046}
6147
62- describe ( 'createTableWriteProvenanceTargets' , ( ) => {
63- it ( 'maps column names to their storage ids' , ( ) => {
64- const targets = createTableWriteProvenanceTargets ( [ { email : 'a@b.c' } ] , translateNames )
65-
66- expect ( targets ) . toEqual ( [
67- {
68- selectionKey : tableRowSecretProvenanceSelectionKey ( 0 , 'email' ) ,
69- rowKey : '0' ,
70- columnId : 'col_email' ,
71- } ,
72- ] )
73- } )
74-
75- it ( 'returns a null column id for a column the wire translator drops' , ( ) => {
76- const targets = createTableWriteProvenanceTargets (
77- [ { email : 'a@b.c' , notAColumn : 'x' } ] ,
78- translateNames
79- )
80-
81- expect ( targets ) . toHaveLength ( 2 )
82- expect ( targets [ 0 ] . columnId ) . toBe ( 'col_email' )
83- expect ( targets [ 1 ] ) . toEqual ( {
84- selectionKey : tableRowSecretProvenanceSelectionKey ( 0 , 'notAColumn' ) ,
85- rowKey : '0' ,
86- columnId : null ,
87- } )
88- } )
89-
90- it ( 'keeps one target per submitted column so bundle selections stay paired' , ( ) => {
91- const targets = createTableWriteProvenanceTargets (
92- [ { notAColumn : 'x' , alsoNotAColumn : 'y' } ] ,
93- translateNames
94- )
95-
96- expect ( targets . map ( ( target ) => target . columnId ) ) . toEqual ( [ null , null ] )
97- } )
98-
99- it ( 'passes column ids through for identity (session) translation' , ( ) => {
100- const targets = createTableWriteProvenanceTargets ( [ { col_email : 'a@b.c' } ] , translateIdentity )
101-
102- expect ( targets [ 0 ] . columnId ) . toBe ( 'col_email' )
103- } )
104-
105- it ( 'keys targets by row index across multiple rows' , ( ) => {
106- const targets = createTableWriteProvenanceTargets (
107- [ { email : 'a@b.c' } , { company : 'Acme' } ] ,
108- translateNames
109- )
110-
111- expect ( targets . map ( ( target ) => target . rowKey ) ) . toEqual ( [ '0' , '1' ] )
112- expect ( targets [ 1 ] . selectionKey ) . toBe ( tableRowSecretProvenanceSelectionKey ( 1 , 'company' ) )
113- } )
114- } )
115-
116- describe ( 'resolveTableWriteSecretProvenance' , ( ) => {
117- it ( 'records no provenance for a dropped column on an unsupported session write' , ( ) => {
118- const rows = [ { email : 'a@b.c' , notAColumn : 'x' } ]
119- const result = resolveTableWriteSecretProvenance ( {
120- request : createMockRequest ( 'POST' , { rows } ) ,
121- payload : { rows } ,
122- authType : AuthType . SESSION ,
123- userId : USER_ID ,
124- workspaceId : WORKSPACE_ID ,
125- targets : createTableWriteProvenanceTargets ( rows , translateNames ) ,
126- rowKeys : [ '0' ] ,
127- } )
128-
129- expect ( result . success ) . toBe ( true )
130- if ( ! result . success ) return
131- expect ( Object . keys ( result . provenanceByRowKey ?. [ '0' ] . columns ?? { } ) ) . toEqual ( [ 'col_email' ] )
132- } )
133-
134- it ( 'accepts a complete bundle that covers a dropped column' , ( ) => {
135- const rows = [ { email : 'a@b.c' , notAColumn : 'x' } ]
136- const { request, payload } = bundleRequest ( [
137- tableRowSecretProvenanceSelectionKey ( 0 , 'email' ) ,
138- tableRowSecretProvenanceSelectionKey ( 0 , 'notAColumn' ) ,
139- ] )
140-
141- const result = resolveTableWriteSecretProvenance ( {
142- request,
143- payload,
144- authType : AuthType . INTERNAL_JWT ,
145- userId : USER_ID ,
146- workspaceId : WORKSPACE_ID ,
147- targets : createTableWriteProvenanceTargets ( rows , translateNames ) ,
148- rowKeys : [ '0' ] ,
149- } )
150-
151- expect ( result . success ) . toBe ( true )
152- if ( ! result . success ) return
153- expect ( Object . keys ( result . provenanceByRowKey ?. [ '0' ] . columns ?? { } ) ) . toEqual ( [ 'col_email' ] )
154- } )
155-
156- it ( 'stores provenance for a fully translatable bundle' , ( ) => {
157- const rows = [ { email : 'a@b.c' , company : 'Acme' } ]
158- const { request, payload } = bundleRequest ( [
159- tableRowSecretProvenanceSelectionKey ( 0 , 'email' ) ,
160- tableRowSecretProvenanceSelectionKey ( 0 , 'company' ) ,
161- ] )
162-
163- const result = resolveTableWriteSecretProvenance ( {
164- request,
165- payload,
166- authType : AuthType . INTERNAL_JWT ,
167- userId : USER_ID ,
168- workspaceId : WORKSPACE_ID ,
169- targets : createTableWriteProvenanceTargets ( rows , translateNames ) ,
170- rowKeys : [ '0' ] ,
171- } )
172-
173- expect ( result . success ) . toBe ( true )
174- if ( ! result . success ) return
175- expect ( Object . keys ( result . provenanceByRowKey ?. [ '0' ] . columns ?? { } ) . sort ( ) ) . toEqual ( [
176- 'col_company' ,
177- 'col_email' ,
178- ] )
179- } )
180-
181- it ( 'rejects a bundle whose selection matches no submitted column' , ( ) => {
182- const rows = [ { email : 'a@b.c' } ]
183- const { request, payload } = bundleRequest ( [ tableRowSecretProvenanceSelectionKey ( 0 , 'company' ) ] )
184-
185- const result = resolveTableWriteSecretProvenance ( {
186- request,
187- payload,
188- authType : AuthType . INTERNAL_JWT ,
189- userId : USER_ID ,
190- workspaceId : WORKSPACE_ID ,
191- targets : createTableWriteProvenanceTargets ( rows , translateNames ) ,
192- rowKeys : [ '0' ] ,
193- } )
194-
195- expect ( result . success ) . toBe ( false )
196- } )
197-
198- it ( 'accepts a different source user in the authorized destination workspace' , ( ) => {
199- const rows = [ { email : 'a@b.c' } ]
200- const payload = {
201- [ PRIVATE_SECRET_PROVENANCE_FIELD ] : {
202- version : 1 ,
203- complete : true ,
204- selections : [
205- {
206- key : tableRowSecretProvenanceSelectionKey ( 0 , 'email' ) ,
207- provenance : {
208- ...traceProvenance ( ) ,
209- scope : { userId : 'someone-else' , workspaceId : WORKSPACE_ID } ,
210- } ,
211- } ,
212- ] ,
213- } ,
214- }
215-
216- const result = resolveTableWriteSecretProvenance ( {
217- request : createMockRequest ( 'POST' , payload , {
218- [ PRIVATE_SECRET_PROVENANCE_HEADER ] : PRIVATE_SECRET_PROVENANCE_BUNDLE_V1 ,
219- } ) ,
220- payload,
221- authType : AuthType . INTERNAL_JWT ,
222- userId : USER_ID ,
223- workspaceId : WORKSPACE_ID ,
224- targets : createTableWriteProvenanceTargets ( rows , translateNames ) ,
225- rowKeys : [ '0' ] ,
226- } )
227-
228- expect ( result . success ) . toBe ( true )
229- if ( ! result . success ) return
230- expect ( result . provenanceByRowKey ?. [ '0' ] . columns . col_email ) . toMatchObject ( {
231- scope : { userId : 'someone-else' , workspaceId : WORKSPACE_ID } ,
232- } )
233- } )
234-
235- it ( 'rejects a bundle whose selection comes from another workspace' , ( ) => {
236- const rows = [ { email : 'a@b.c' } ]
237- const payload = {
238- [ PRIVATE_SECRET_PROVENANCE_FIELD ] : {
239- version : 1 ,
240- complete : true ,
241- selections : [
242- {
243- key : tableRowSecretProvenanceSelectionKey ( 0 , 'email' ) ,
244- provenance : {
245- ...traceProvenance ( ) ,
246- scope : { userId : USER_ID , workspaceId : 'another-workspace' } ,
247- } ,
248- } ,
249- ] ,
250- } ,
251- }
252-
253- const result = resolveTableWriteSecretProvenance ( {
254- request : createMockRequest ( 'POST' , payload , {
255- [ PRIVATE_SECRET_PROVENANCE_HEADER ] : PRIVATE_SECRET_PROVENANCE_BUNDLE_V1 ,
256- } ) ,
257- payload,
258- authType : AuthType . INTERNAL_JWT ,
259- userId : USER_ID ,
260- workspaceId : WORKSPACE_ID ,
261- targets : createTableWriteProvenanceTargets ( rows , translateNames ) ,
262- rowKeys : [ '0' ] ,
263- } )
264-
265- expect ( result . success ) . toBe ( false )
266- } )
267- } )
268-
269- /**
270- * The transport half of the envelope, used by the migrated single-row routes.
271- *
272- * These are the only cover these helpers have: the route tests assert `mapInput`
273- * and `present`, so each helper could be replaced by a constant without a route
274- * test noticing — and a constant `readTableRowProvenanceEnvelope` would silently
275- * downgrade every executor write from a stamped bundle to untracked.
276- */
27748describe ( 'readTableRowProvenanceEnvelope' , ( ) => {
27849 it ( 'reports no envelope when the caller sent none' , ( ) => {
27950 const request = createMockRequest ( 'PATCH' , { data : { } } )
0 commit comments