4343 },
4444 }
4545
46- result := generateSafeOutputsConfig (data )
46+ result , err := generateSafeOutputsConfig (data )
47+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
4748 require .NotEmpty (t , result , "Expected non-empty config" )
4849
4950 var parsed map [string ]any
5960 assert .Equal (t , ".lock.yml" , workflowFiles ["ci" ], "ci should map to .lock.yml" )
6061}
6162
63+ // TestGenerateSafeOutputsConfigActions tests that generateSafeOutputsConfig includes custom
64+ // action tool names as enabled keys so both MCP server implementations register them.
65+ func TestGenerateSafeOutputsConfigActions (t * testing.T ) {
66+ data := & WorkflowData {
67+ SafeOutputs : & SafeOutputsConfig {
68+ Actions : map [string ]* SafeOutputActionConfig {
69+ "upload_report" : {
70+ Uses : "actions/upload-artifact@v4" ,
71+ Description : "Upload the report" ,
72+ },
73+ "publish-results" : {
74+ Uses : "owner/action@v1" ,
75+ Description : "Publish results" ,
76+ },
77+ },
78+ },
79+ }
80+
81+ result , err := generateSafeOutputsConfig (data )
82+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
83+ require .NotEmpty (t , result , "Expected non-empty config" )
84+
85+ var parsed map [string ]any
86+ require .NoError (t , json .Unmarshal ([]byte (result ), & parsed ), "Result must be valid JSON" )
87+
88+ // Each action tool should appear as a truthy key in config.json so the MCP server
89+ // registers it. Names are normalized (hyphens converted to underscores).
90+ uploadVal , hasUploadReport := parsed ["upload_report" ]
91+ assert .True (t , hasUploadReport , "Expected upload_report key in config" )
92+ assert .Equal (t , true , uploadVal , "upload_report value should be true" )
93+
94+ publishVal , hasPublishResults := parsed ["publish_results" ]
95+ assert .True (t , hasPublishResults , "Expected publish_results key in config (hyphen normalized to underscore)" )
96+ assert .Equal (t , true , publishVal , "publish_results value should be true" )
97+ }
98+
99+ // TestGenerateSafeOutputsConfigActionsCollisionReturnsError tests that a custom action
100+ // whose normalized name collides with an existing built-in handler key returns an error.
101+ func TestGenerateSafeOutputsConfigActionsCollisionReturnsError (t * testing.T ) {
102+ trueVal := "true"
103+ data := & WorkflowData {
104+ SafeOutputs : & SafeOutputsConfig {
105+ // add_labels is a built-in handler that produces a real config object.
106+ AddLabels : & AddLabelsConfig {
107+ Allowed : []string {"bug" },
108+ },
109+ // A custom action whose normalized name matches the built-in "add_labels" key.
110+ Actions : map [string ]* SafeOutputActionConfig {
111+ "add-labels" : {
112+ Uses : "owner/some-action@v1" ,
113+ Description : "Should trigger a collision error" ,
114+ },
115+ },
116+ // Ensure at least one handler is set to make config non-empty.
117+ NoOp : & NoOpConfig {BaseSafeOutputConfig : BaseSafeOutputConfig {Max : & trueVal }},
118+ },
119+ }
120+
121+ _ , err := generateSafeOutputsConfig (data )
122+ require .Error (t , err , "Expected an error when a custom action name collides with a built-in handler key" )
123+ assert .Contains (t , err .Error (), "add-labels" , "Error should mention the conflicting action name" )
124+ assert .Contains (t , err .Error (), "add_labels" , "Error should mention the conflicting normalized name" )
125+ }
126+
62127// TestGenerateSafeOutputsConfigMissingToolWithIssue tests the missing_tool config.
63128// The legacy create_missing_tool_issue sub-key is no longer generated; only missing_tool is present.
64129func TestGenerateSafeOutputsConfigMissingToolWithIssue (t * testing.T ) {
@@ -73,7 +138,8 @@ func TestGenerateSafeOutputsConfigMissingToolWithIssue(t *testing.T) {
73138 },
74139 }
75140
76- result := generateSafeOutputsConfig (data )
141+ result , err := generateSafeOutputsConfig (data )
142+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
77143 require .NotEmpty (t , result , "Expected non-empty config" )
78144
79145 var parsed map [string ]any
@@ -105,7 +171,8 @@ func TestGenerateSafeOutputsConfigMentions(t *testing.T) {
105171 },
106172 }
107173
108- result := generateSafeOutputsConfig (data )
174+ result , err := generateSafeOutputsConfig (data )
175+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
109176 require .NotEmpty (t , result , "Expected non-empty config" )
110177
111178 var parsed map [string ]any
@@ -347,7 +414,8 @@ func TestGenerateSafeOutputsConfigAddLabelsBlocked(t *testing.T) {
347414 },
348415 }
349416
350- result := generateSafeOutputsConfig (data )
417+ result , err := generateSafeOutputsConfig (data )
418+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
351419 require .NotEmpty (t , result , "Expected non-empty config" )
352420
353421 var parsed map [string ]any
@@ -386,7 +454,8 @@ func TestGenerateSafeOutputsConfigCreatePullRequestTargetRepo(t *testing.T) {
386454 },
387455 }
388456
389- result := generateSafeOutputsConfig (data )
457+ result , err := generateSafeOutputsConfig (data )
458+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
390459 require .NotEmpty (t , result , "Expected non-empty config" )
391460
392461 var parsed map [string ]any
@@ -429,7 +498,8 @@ func TestGenerateSafeOutputsConfigCreatePullRequestBackwardCompat(t *testing.T)
429498 },
430499 }
431500
432- result := generateSafeOutputsConfig (data )
501+ result , err := generateSafeOutputsConfig (data )
502+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
433503 require .NotEmpty (t , result , "Expected non-empty config" )
434504
435505 var parsed map [string ]any
@@ -462,7 +532,8 @@ func TestGenerateSafeOutputsConfigCreatePullRequestAutoCloseIssue(t *testing.T)
462532 },
463533 }
464534
465- result := generateSafeOutputsConfig (data )
535+ result , err := generateSafeOutputsConfig (data )
536+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
466537 require .NotEmpty (t , result , "Expected non-empty config" )
467538
468539 var parsed map [string ]any
@@ -487,7 +558,8 @@ func TestGenerateSafeOutputsConfigCreatePullRequestAutoCloseIssueExpression(t *t
487558 },
488559 }
489560
490- result := generateSafeOutputsConfig (data )
561+ result , err := generateSafeOutputsConfig (data )
562+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
491563 require .NotEmpty (t , result , "Expected non-empty config" )
492564
493565 var parsed map [string ]any
@@ -510,7 +582,8 @@ func TestGenerateSafeOutputsConfigCreatePullRequestAutoCloseIssueOmittedByDefaul
510582 },
511583 }
512584
513- result := generateSafeOutputsConfig (data )
585+ result , err := generateSafeOutputsConfig (data )
586+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
514587 require .NotEmpty (t , result , "Expected non-empty config" )
515588
516589 var parsed map [string ]any
@@ -546,7 +619,8 @@ func TestGenerateSafeOutputsConfigRepoMemory(t *testing.T) {
546619 },
547620 }
548621
549- result := generateSafeOutputsConfig (data )
622+ result , err := generateSafeOutputsConfig (data )
623+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
550624 require .NotEmpty (t , result , "Expected non-empty config" )
551625
552626 var parsed map [string ]any
@@ -586,7 +660,8 @@ func TestGenerateSafeOutputsConfigNoRepoMemory(t *testing.T) {
586660 RepoMemoryConfig : nil ,
587661 }
588662
589- result := generateSafeOutputsConfig (data )
663+ result , err := generateSafeOutputsConfig (data )
664+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
590665 require .NotEmpty (t , result , "Expected non-empty config" )
591666
592667 var parsed map [string ]any
@@ -609,7 +684,8 @@ func TestGenerateSafeOutputsConfigEmptyRepoMemory(t *testing.T) {
609684 },
610685 }
611686
612- result := generateSafeOutputsConfig (data )
687+ result , err := generateSafeOutputsConfig (data )
688+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
613689 require .NotEmpty (t , result , "Expected non-empty config" )
614690
615691 var parsed map [string ]any
@@ -632,7 +708,8 @@ func TestGenerateSafeOutputsConfigReplyToPullRequestReviewComment(t *testing.T)
632708 },
633709 }
634710
635- result := generateSafeOutputsConfig (data )
711+ result , err := generateSafeOutputsConfig (data )
712+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
636713 require .NotEmpty (t , result , "Expected non-empty config" )
637714
638715 var parsed map [string ]any
@@ -661,7 +738,8 @@ func TestGenerateSafeOutputsConfigReplyToPullRequestReviewCommentWithTarget(t *t
661738 },
662739 }
663740
664- result := generateSafeOutputsConfig (data )
741+ result , err := generateSafeOutputsConfig (data )
742+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
665743 require .NotEmpty (t , result , "Expected non-empty config" )
666744
667745 var parsed map [string ]any
@@ -705,7 +783,8 @@ func TestGenerateSafeOutputsConfigClosePullRequest(t *testing.T) {
705783 },
706784 }
707785
708- result := generateSafeOutputsConfig (data )
786+ result , err := generateSafeOutputsConfig (data )
787+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
709788 require .NotEmpty (t , result , "Expected non-empty config" )
710789
711790 var parsed map [string ]any
@@ -743,7 +822,8 @@ func TestGenerateSafeOutputsConfigClosePullRequestStaged(t *testing.T) {
743822 },
744823 }
745824
746- result := generateSafeOutputsConfig (data )
825+ result , err := generateSafeOutputsConfig (data )
826+ require .NoError (t , err , "generateSafeOutputsConfig should not return an error" )
747827 require .NotEmpty (t , result , "Expected non-empty config" )
748828
749829 var parsed map [string ]any
0 commit comments