@@ -428,3 +428,124 @@ This workflow needs permissions.`
428428 assert .Contains (t , result , "# Test Workflow" )
429429 assert .Contains (t , result , "This workflow needs permissions." )
430430}
431+
432+ func TestWritePermissionsCodemod_SkipsIdToken (t * testing.T ) {
433+ codemod := getMigrateWritePermissionsToReadCodemod ()
434+
435+ content := `---
436+ on: workflow_dispatch
437+ permissions:
438+ contents: read
439+ id-token: write
440+ ---
441+
442+ # Test`
443+
444+ frontmatter := map [string ]any {
445+ "on" : "workflow_dispatch" ,
446+ "permissions" : map [string ]any {
447+ "contents" : "read" ,
448+ "id-token" : "write" ,
449+ },
450+ }
451+
452+ result , applied , err := codemod .Apply (content , frontmatter )
453+
454+ require .NoError (t , err , "codemod should not return an error" )
455+ assert .False (t , applied , "Should not be applied when only write-only permissions have write" )
456+ assert .Equal (t , content , result , "codemod result should be unchanged when only write-only permissions have write" )
457+ assert .Contains (t , result , "id-token: write" , "id-token permission should remain write after codemod" )
458+ assert .NotContains (t , result , "id-token: read" , "id-token should never be converted to read" )
459+ }
460+
461+ func TestWritePermissionsCodemod_SkipsCopilotRequests (t * testing.T ) {
462+ codemod := getMigrateWritePermissionsToReadCodemod ()
463+
464+ content := `---
465+ on: workflow_dispatch
466+ permissions:
467+ contents: read
468+ copilot-requests: write
469+ ---
470+
471+ # Test`
472+
473+ frontmatter := map [string ]any {
474+ "on" : "workflow_dispatch" ,
475+ "permissions" : map [string ]any {
476+ "contents" : "read" ,
477+ "copilot-requests" : "write" ,
478+ },
479+ }
480+
481+ result , applied , err := codemod .Apply (content , frontmatter )
482+
483+ require .NoError (t , err , "codemod should not return an error" )
484+ assert .False (t , applied , "Should not be applied when only write-only permissions have write" )
485+ assert .Equal (t , content , result , "codemod result should be unchanged when only write-only permissions have write" )
486+ assert .Contains (t , result , "copilot-requests: write" , "copilot-requests permission should remain write after codemod" )
487+ assert .NotContains (t , result , "copilot-requests: read" , "copilot-requests should never be converted to read" )
488+ }
489+
490+ func TestWritePermissionsCodemod_MixedWithIdToken (t * testing.T ) {
491+ codemod := getMigrateWritePermissionsToReadCodemod ()
492+
493+ content := `---
494+ on: workflow_dispatch
495+ permissions:
496+ contents: write
497+ issues: write
498+ id-token: write
499+ ---
500+
501+ # Test`
502+
503+ frontmatter := map [string ]any {
504+ "on" : "workflow_dispatch" ,
505+ "permissions" : map [string ]any {
506+ "contents" : "write" ,
507+ "issues" : "write" ,
508+ "id-token" : "write" ,
509+ },
510+ }
511+
512+ result , applied , err := codemod .Apply (content , frontmatter )
513+
514+ require .NoError (t , err , "codemod should not return an error" )
515+ assert .True (t , applied , "codemod should be applied when non-write-only permissions have write" )
516+ assert .Contains (t , result , "contents: read" , "contents permission should be downgraded from write to read" )
517+ assert .Contains (t , result , "issues: read" , "issues permission should be downgraded from write to read" )
518+ // id-token must remain write — "read" is not a valid value for it
519+ assert .Contains (t , result , "id-token: write" , "id-token permission should remain write after codemod" )
520+ assert .NotContains (t , result , "id-token: read" , "id-token should never be converted to read" )
521+ }
522+
523+ func TestWritePermissionsCodemod_MixedWithCopilotRequests (t * testing.T ) {
524+ codemod := getMigrateWritePermissionsToReadCodemod ()
525+
526+ content := `---
527+ on: workflow_dispatch
528+ permissions:
529+ contents: write
530+ copilot-requests: write
531+ ---
532+
533+ # Test`
534+
535+ frontmatter := map [string ]any {
536+ "on" : "workflow_dispatch" ,
537+ "permissions" : map [string ]any {
538+ "contents" : "write" ,
539+ "copilot-requests" : "write" ,
540+ },
541+ }
542+
543+ result , applied , err := codemod .Apply (content , frontmatter )
544+
545+ require .NoError (t , err , "codemod should not return an error" )
546+ assert .True (t , applied , "codemod should be applied when non-write-only permissions have write" )
547+ assert .Contains (t , result , "contents: read" , "contents permission should be downgraded from write to read" )
548+ // copilot-requests must remain write — "read" is not a valid value for it
549+ assert .Contains (t , result , "copilot-requests: write" , "copilot-requests permission should remain write after codemod" )
550+ assert .NotContains (t , result , "copilot-requests: read" , "copilot-requests should never be converted to read" )
551+ }
0 commit comments