@@ -1098,6 +1098,122 @@ describe("add_comment", () => {
10981098 expect ( capturedBody ) . not . toContain ( "aw_test02" ) ;
10991099 } ) ;
11001100 } ) ;
1101+
1102+ describe ( "sanitization preserves markers" , ( ) => {
1103+ it ( "should preserve tracker ID markers after sanitization" , async ( ) => {
1104+ const addCommentScript = fs . readFileSync ( path . join ( __dirname , "add_comment.cjs" ) , "utf8" ) ;
1105+
1106+ // Setup environment
1107+ process . env . GH_AW_WORKFLOW_NAME = "Test Workflow" ;
1108+ process . env . GH_AW_TRACKER_ID = "test-tracker-123" ;
1109+
1110+ let capturedBody = null ;
1111+ mockGithub . rest . issues . createComment = async params => {
1112+ capturedBody = params . body ;
1113+ return {
1114+ data : {
1115+ id : 12345 ,
1116+ html_url : "https://github.com/owner/repo/issues/42#issuecomment-12345" ,
1117+ } ,
1118+ } ;
1119+ } ;
1120+
1121+ // Execute the handler
1122+ const handler = await eval ( `(async () => { ${ addCommentScript } ; return await main({}); })()` ) ;
1123+
1124+ const message = {
1125+ type : "add_comment" ,
1126+ body : "User content with <script>alert('xss')</script> attempt" ,
1127+ } ;
1128+
1129+ const result = await handler ( message , { } ) ;
1130+
1131+ expect ( result . success ) . toBe ( true ) ;
1132+ expect ( capturedBody ) . toBeDefined ( ) ;
1133+ // Verify tracker ID is present (not removed by sanitization)
1134+ expect ( capturedBody ) . toContain ( "<!-- gh-aw-tracker-id: test-tracker-123 -->" ) ;
1135+ // Verify script tags were sanitized (converted to safe format)
1136+ expect ( capturedBody ) . not . toContain ( "<script>" ) ;
1137+ expect ( capturedBody ) . toContain ( "(script)" ) ; // Tags converted to parentheses
1138+
1139+ delete process . env . GH_AW_WORKFLOW_NAME ;
1140+ delete process . env . GH_AW_TRACKER_ID ;
1141+ } ) ;
1142+
1143+ it ( "should preserve workflow footer after sanitization" , async ( ) => {
1144+ const addCommentScript = fs . readFileSync ( path . join ( __dirname , "add_comment.cjs" ) , "utf8" ) ;
1145+
1146+ // Setup environment
1147+ process . env . GH_AW_WORKFLOW_NAME = "Security Test Workflow" ;
1148+
1149+ let capturedBody = null ;
1150+ mockGithub . rest . issues . createComment = async params => {
1151+ capturedBody = params . body ;
1152+ return {
1153+ data : {
1154+ id : 12345 ,
1155+ html_url : "https://github.com/owner/repo/issues/42#issuecomment-12345" ,
1156+ } ,
1157+ } ;
1158+ } ;
1159+
1160+ // Execute the handler
1161+ const handler = await eval ( `(async () => { ${ addCommentScript } ; return await main({}); })()` ) ;
1162+
1163+ const message = {
1164+ type : "add_comment" ,
1165+ body : "User content <!-- malicious comment -->" ,
1166+ } ;
1167+
1168+ const result = await handler ( message , { } ) ;
1169+
1170+ expect ( result . success ) . toBe ( true ) ;
1171+ expect ( capturedBody ) . toBeDefined ( ) ;
1172+ // Verify AI footer is present (not removed by sanitization)
1173+ expect ( capturedBody ) . toContain ( "AI generated by" ) ;
1174+ expect ( capturedBody ) . toContain ( "Security Test Workflow" ) ;
1175+ // Verify malicious comment in user content was removed by sanitization
1176+ expect ( capturedBody ) . not . toContain ( "<!-- malicious comment -->" ) ;
1177+
1178+ delete process . env . GH_AW_WORKFLOW_NAME ;
1179+ } ) ;
1180+
1181+ it ( "should sanitize user content but preserve system markers" , async ( ) => {
1182+ const addCommentScript = fs . readFileSync ( path . join ( __dirname , "add_comment.cjs" ) , "utf8" ) ;
1183+
1184+ let capturedBody = null ;
1185+ mockGithub . rest . issues . createComment = async params => {
1186+ capturedBody = params . body ;
1187+ return {
1188+ data : {
1189+ id : 12345 ,
1190+ html_url : "https://github.com/owner/repo/issues/42#issuecomment-12345" ,
1191+ } ,
1192+ } ;
1193+ } ;
1194+
1195+ // Execute the handler
1196+ const handler = await eval ( `(async () => { ${ addCommentScript } ; return await main({}); })()` ) ;
1197+
1198+ const message = {
1199+ type : "add_comment" ,
1200+ body : "User says: @badactor please <!-- inject this --> [phishing](http://evil.com)" ,
1201+ } ;
1202+
1203+ const result = await handler ( message , { } ) ;
1204+
1205+ expect ( result . success ) . toBe ( true ) ;
1206+ expect ( capturedBody ) . toBeDefined ( ) ;
1207+
1208+ // User content should be sanitized
1209+ expect ( capturedBody ) . toContain ( "`@badactor`" ) ; // Mention neutralized
1210+ expect ( capturedBody ) . not . toContain ( "<!-- inject this -->" ) ; // Comment removed
1211+ expect ( capturedBody ) . toContain ( "(evil.com/redacted)" ) ; // HTTP URL redacted
1212+
1213+ // But footer should still be present with proper markdown
1214+ expect ( capturedBody ) . toContain ( "> AI generated by" ) ;
1215+ } ) ;
1216+ } ) ;
11011217} ) ;
11021218
11031219describe ( "enforceCommentLimits" , ( ) => {
0 commit comments