@@ -584,6 +584,60 @@ describe("buildGatewayCronService", () => {
584584 }
585585 } ) ;
586586
587+ it ( "redacts command cron summaries before webhook delivery without changing stored run state" , async ( ) => {
588+ const cfg = createCronConfig ( "server-cron-command-webhook-redaction" ) ;
589+ loadConfigMock . mockReturnValue ( cfg ) ;
590+ fetchWithSsrFGuardMock . mockResolvedValue ( { release : vi . fn ( async ( ) => { } ) } ) ;
591+
592+ const state = buildGatewayCronService ( {
593+ cfg,
594+ deps : { } as CliDeps ,
595+ broadcast : ( ) => { } ,
596+ } ) ;
597+ try {
598+ const job = await state . cron . add ( {
599+ name : "redacted-command-webhook" ,
600+ enabled : true ,
601+ deleteAfterRun : false ,
602+ schedule : { kind : "at" , at : new Date ( 1 ) . toISOString ( ) } ,
603+ sessionTarget : "isolated" ,
604+ wakeMode : "next-heartbeat" ,
605+ payload : {
606+ kind : "command" ,
607+ argv : [
608+ process . execPath ,
609+ "-e" ,
610+ [
611+ "process.stdout.write('Open https://microsoft.com/devicelogin and enter code ABCD-EFGH\\n')" ,
612+ "process.stdout.write('OPENAI_API_KEY=sk-1234567890abcdef\\n')" ,
613+ ] . join ( ";" ) ,
614+ ] ,
615+ } ,
616+ delivery : {
617+ mode : "webhook" ,
618+ to : "https://example.invalid/cron-finished" ,
619+ } ,
620+ } ) ;
621+
622+ await state . cron . run ( job . id , "force" ) ;
623+
624+ expect ( fetchWithSsrFGuardMock ) . toHaveBeenCalledTimes ( 1 ) ;
625+ const request = requireRecord (
626+ callArg ( fetchWithSsrFGuardMock , 0 , 0 , "webhook request" ) ,
627+ "webhook request" ,
628+ ) ;
629+ const init = requireRecord ( request . init , "webhook init" ) ;
630+ const payload = JSON . parse ( String ( init . body ) ) as { summary ?: string } ;
631+ expect ( payload . summary ) . toContain ( "[redacted device authorization output]" ) ;
632+ expect ( payload . summary ) . toContain ( "OPENAI_API_KEY=sk-123…cdef" ) ;
633+ expect ( payload . summary ) . not . toContain ( "ABCD-EFGH" ) ;
634+ expect ( payload . summary ) . not . toContain ( "sk-1234567890abcdef" ) ;
635+ expect ( state . cron . getJob ( job . id ) ?. state . lastDiagnosticSummary ) . toContain ( "ABCD-EFGH" ) ;
636+ } finally {
637+ state . cron . stop ( ) ;
638+ }
639+ } ) ;
640+
587641 it ( "routes global-scope main cron jobs through the global queue for queued wakes" , async ( ) => {
588642 const cfg = {
589643 ...createCronConfig ( "server-cron-global-queued" ) ,
0 commit comments