@@ -110,6 +110,131 @@ describe('TelemetrySubscriber', () => {
110110 }
111111 } ) ;
112112
113+ it ( 'does not collect producer identities from local-sensitive or secret extension events' , async ( ) => {
114+ const LOCAL_PRIVATE_SOURCE : IReporterEventSource = {
115+ packageName : '@private/local-reporter-plugin' ,
116+ packageVersion : '1.2.3-private'
117+ } ;
118+ const SECRET_PRIVATE_SOURCE : IReporterEventSource = {
119+ packageName : '@private/secret-reporter-plugin' ,
120+ packageVersion : '4.5.6-secret'
121+ } ;
122+ const telemetry : TelemetrySubscriber = new TelemetrySubscriber ( ) ;
123+ const manager : ReporterManager = new ReporterManager ( ) ;
124+ manager . addReporter ( createTelemetryReporter ( telemetry ) ) ;
125+ await manager . initializeAsync ( ) ;
126+
127+ manager . emit ( {
128+ ...rawInput ( 'extension' , { name : 'private.local.event' , privateField : 'local-private-value' } ) ,
129+ source : LOCAL_PRIVATE_SOURCE ,
130+ privacy : 'local-sensitive'
131+ } ) ;
132+ manager . emit ( {
133+ ...rawInput ( 'extension' , { name : 'private.secret.event' , secretField : 'secret-private-value' } ) ,
134+ source : SECRET_PRIVATE_SOURCE ,
135+ privacy : 'secret'
136+ } ) ;
137+ await manager . flushAsync ( ) ;
138+
139+ const aggregate : ITelemetryAggregate = telemetry . buildAggregate ( ) ;
140+ const serialized : string = JSON . stringify ( aggregate ) ;
141+ expect ( aggregate . producerVersions ) . toEqual ( [ ] ) ;
142+ expect ( aggregate . protocolVersion ) . toBeUndefined ( ) ;
143+ for ( const forbidden of [
144+ LOCAL_PRIVATE_SOURCE . packageName ,
145+ LOCAL_PRIVATE_SOURCE . packageVersion ,
146+ SECRET_PRIVATE_SOURCE . packageName ,
147+ SECRET_PRIVATE_SOURCE . packageVersion ,
148+ 'local-private-value' ,
149+ 'secret-private-value'
150+ ] ) {
151+ expect ( serialized ) . not . toContain ( forbidden ) ;
152+ }
153+ } ) ;
154+
155+ it ( 'projects only public envelopes while aggregating public producers deterministically' , async ( ) => {
156+ const PUBLIC_EXTENSION_SOURCE : IReporterEventSource = {
157+ packageName : '@rushstack/public-reporter-plugin' ,
158+ packageVersion : '1.2.3'
159+ } ;
160+ const PRIVATE_FIRST_PARTY_SOURCE : IReporterEventSource = {
161+ packageName : '@microsoft/internal-build-plugin' ,
162+ packageVersion : '9.8.7-private'
163+ } ;
164+ const telemetry : TelemetrySubscriber = new TelemetrySubscriber ( ) ;
165+ const manager : ReporterManager = new ReporterManager ( ) ;
166+ manager . addReporter ( createTelemetryReporter ( telemetry ) ) ;
167+ await manager . initializeAsync ( ) ;
168+
169+ manager . emit ( {
170+ ...rawInput ( 'commandResult' , {
171+ commandName : 'private-command' ,
172+ succeeded : false ,
173+ exitCode : 97
174+ } ) ,
175+ source : PRIVATE_FIRST_PARTY_SOURCE ,
176+ privacy : 'local-sensitive' ,
177+ protocolVersion : { major : 7 , minor : 0 }
178+ } ) ;
179+ manager . emit ( {
180+ ...rawInput ( 'extension' , { name : 'public.plugin.event' } ) ,
181+ source : PUBLIC_EXTENSION_SOURCE
182+ } ) ;
183+ manager . emit ( rawInput ( 'commandResult' , { commandName : 'build' , succeeded : true , exitCode : 0 } ) ) ;
184+ manager . emit ( {
185+ ...rawInput ( 'extension' , { name : 'public.plugin.event' } ) ,
186+ source : PUBLIC_EXTENSION_SOURCE
187+ } ) ;
188+ manager . emit ( rawInput ( 'diagnosticEmitted' , { code : 'RUSH_OPERATION_FAILED' , category : 'operation' } ) ) ;
189+ manager . emit ( {
190+ ...rawInput ( 'operationStatusChanged' , {
191+ operationId : 'private-operation' ,
192+ status : 'failure'
193+ } ) ,
194+ source : PRIVATE_FIRST_PARTY_SOURCE ,
195+ privacy : 'local-sensitive'
196+ } ) ;
197+ manager . emit ( {
198+ ...rawInput ( 'diagnosticEmitted' , {
199+ code : 'PRIVATE_INTERNAL_DIAGNOSTIC' ,
200+ category : 'private-category'
201+ } ) ,
202+ source : PRIVATE_FIRST_PARTY_SOURCE ,
203+ privacy : 'secret'
204+ } ) ;
205+ manager . emit ( rawInput ( 'operationStatusChanged' , { operationId : 'public-operation' , status : 'success' } ) ) ;
206+ manager . emit ( {
207+ ...rawInput ( 'extension' , { name : 'private.secret.event' } ) ,
208+ source : PRIVATE_FIRST_PARTY_SOURCE ,
209+ privacy : 'secret' ,
210+ protocolVersion : { major : 99 , minor : 0 }
211+ } ) ;
212+ await manager . flushAsync ( ) ;
213+
214+ const aggregate : ITelemetryAggregate = telemetry . buildAggregate ( ) ;
215+ expect ( aggregate ) . toMatchObject ( {
216+ commandName : 'build' ,
217+ result : 'succeeded' ,
218+ exitCode : 0 ,
219+ operationStatusCounts : { success : 1 } ,
220+ diagnosticCodes : [ 'RUSH_OPERATION_FAILED' ] ,
221+ diagnosticCategoryCounts : { operation : 1 } ,
222+ protocolVersion : { major : 1 , minor : 0 } ,
223+ producerVersions : [ '@microsoft/rush-lib@5.177.2' , '@rushstack/public-reporter-plugin@1.2.3' ]
224+ } ) ;
225+ const serialized : string = JSON . stringify ( aggregate ) ;
226+ for ( const forbidden of [
227+ PRIVATE_FIRST_PARTY_SOURCE . packageName ,
228+ PRIVATE_FIRST_PARTY_SOURCE . packageVersion ,
229+ 'private-command' ,
230+ 'PRIVATE_INTERNAL_DIAGNOSTIC' ,
231+ 'private-category' ,
232+ 'private-operation'
233+ ] ) {
234+ expect ( serialized ) . not . toContain ( forbidden ) ;
235+ }
236+ } ) ;
237+
113238 it ( 'never leaks messages, paths, arguments, remediation, raw output, or secret values' , async ( ) => {
114239 const SECRET : string = 'sk-super-secret-value' ;
115240 const LOG_PATH : string = '/home/user/secret/install.log' ;
0 commit comments