@@ -784,28 +784,30 @@ describe("gateway server cron", () => {
784784 }
785785 } ) ;
786786
787- test ( "rejects unsafe custom session ids on add and update" , async ( ) => {
787+ test ( "accepts opaque custom session ids on add and update" , async ( ) => {
788788 const { prevSkipCron } = await setupCronTestRun ( {
789- tempPrefix : "openclaw-gw-cron-bad -session-target-" ,
789+ tempPrefix : "openclaw-gw-cron-opaque -session-target-" ,
790790 cronEnabled : false ,
791791 } ) ;
792792
793793 const cronState = await createDirectCronState ( ) ;
794794
795795 try {
796796 const addRes = await directCronReq ( cronState , "cron.add" , {
797- name : "bad custom session" ,
797+ name : "dingtalk group session" ,
798798 enabled : true ,
799799 schedule : { kind : "every" , everyMs : 60_000 } ,
800- sessionTarget : "session:../../outside " ,
800+ sessionTarget : "session:agent:main:dingtalk:group:cid3tmd4xb19xjfk/wogxwy2a== " ,
801801 wakeMode : "now" ,
802802 payload : { kind : "agentTurn" , message : "hello" } ,
803803 } ) ;
804- expect ( addRes . ok ) . toBe ( false ) ;
805- expect ( addRes . error ?. message ) . toContain ( "invalid cron sessionTarget session id" ) ;
804+ expect ( addRes . ok ) . toBe ( true ) ;
805+ expectRecordFields ( addRes . payload , {
806+ sessionTarget : "session:agent:main:dingtalk:group:cid3tmd4xb19xjfk/wogxwy2a==" ,
807+ } ) ;
806808
807809 const validRes = await directCronReq ( cronState , "cron.add" , {
808- name : "good custom session" ,
810+ name : "custom session to patch " ,
809811 enabled : true ,
810812 schedule : { kind : "every" , everyMs : 60_000 } ,
811813 sessionTarget : "session:project-alpha:ops" ,
@@ -822,8 +824,8 @@ describe("gateway server cron", () => {
822824 sessionTarget : "session:..\\outside" ,
823825 } ,
824826 } ) ;
825- expect ( updateRes . ok ) . toBe ( false ) ;
826- expect ( updateRes . error ?. message ) . toContain ( "invalid cron sessionTarget session id" ) ;
827+ expect ( updateRes . ok ) . toBe ( true ) ;
828+ expectRecordFields ( updateRes . payload , { sessionTarget : " session:..\\outside" } ) ;
827829 } finally {
828830 await cleanupCronTestRun ( { cronState, prevSkipCron } ) ;
829831 }
@@ -1136,20 +1138,21 @@ describe("gateway server cron", () => {
11361138 }
11371139 } , 45_000 ) ;
11381140
1139- test ( "fails closed for persisted unsafe custom session ids" , async ( ) => {
1141+ test ( "runs persisted opaque custom session ids with native separators " , async ( ) => {
11401142 const now = Date . now ( ) ;
1143+ const sessionTarget = "session:agent:main:dingtalk:group:cid3tmd4xb19xjfk/wogxwy2a==" ;
11411144 const { prevSkipCron } = await setupCronTestRun ( {
1142- tempPrefix : "openclaw-gw-cron-persisted-bad -session-target-" ,
1145+ tempPrefix : "openclaw-gw-cron-persisted-opaque -session-target-" ,
11431146 cronEnabled : false ,
11441147 jobs : [
11451148 {
1146- id : "bad -custom-session-job" ,
1147- name : "bad custom session job" ,
1149+ id : "opaque -custom-session-job" ,
1150+ name : "opaque custom session job" ,
11481151 enabled : true ,
11491152 createdAtMs : now ,
11501153 updatedAtMs : now ,
11511154 schedule : { kind : "every" , everyMs : 60_000 } ,
1152- sessionTarget : "session:../../outside" ,
1155+ sessionTarget,
11531156 wakeMode : "now" ,
11541157 payload : { kind : "agentTurn" , message : "hello" } ,
11551158 state : { } ,
@@ -1162,13 +1165,21 @@ describe("gateway server cron", () => {
11621165 await connectOk ( ws ) ;
11631166
11641167 try {
1168+ const finished = waitForCronEvent (
1169+ ws ,
1170+ ( payload ) =>
1171+ payload ?. jobId === "opaque-custom-session-job" && payload ?. action === "finished" ,
1172+ ) ;
11651173 const runRes = await rpcReq ( ws , "cron.run" , {
1166- id : "bad -custom-session-job" ,
1174+ id : "opaque -custom-session-job" ,
11671175 mode : "force" ,
11681176 } ) ;
11691177 expect ( runRes . ok ) . toBe ( true ) ;
1170- expect ( runRes . payload ) . toEqual ( { ok : true , ran : false , reason : "invalid-spec" } ) ;
1171- expect ( cronIsolatedRun ) . not . toHaveBeenCalled ( ) ;
1178+ expectEnqueuedRunPayload ( runRes . payload ) ;
1179+ await finished ;
1180+ expect ( cronIsolatedRun ) . toHaveBeenCalledTimes ( 1 ) ;
1181+ const call = cronIsolatedRun . mock . calls . at ( 0 ) ?. [ 0 ] as { sessionKey ?: unknown } | undefined ;
1182+ expect ( call ?. sessionKey ) . toBe ( "agent:main:dingtalk:group:cid3tmd4xb19xjfk/wogxwy2a==" ) ;
11721183 } finally {
11731184 await cleanupCronTestRun ( { ws, server, prevSkipCron } ) ;
11741185 }
0 commit comments