@@ -34,3 +34,31 @@ func TestContributionCheckWorkflowSafeOutputContract(t *testing.T) {
3434 assert .Contains (t , text , "\" issue_number\" :35304" , "Workflow should include a concrete add_comment issue_number example" )
3535 assert .Contains (t , text , "model: claude-haiku-4.5" , "Workflow should require small model for contribution-checker subagent calls" )
3636}
37+
38+ func TestContributionCheckWorkflowAllowsRequiredShellCommands (t * testing.T ) {
39+ repoRoot , err := gitutil .FindGitRoot ()
40+ if err != nil {
41+ t .Skipf ("Skipping test: not in a git repository: %v" , err )
42+ }
43+
44+ workflowPath := filepath .Join (repoRoot , ".github" , "workflows" , "contribution-check.md" )
45+ content , err := os .ReadFile (workflowPath )
46+ require .NoError (t , err , "Should read contribution-check workflow" )
47+
48+ text := string (content )
49+ assert .Contains (t , text , `"git"` , "Workflow must allow git fetch/diff commands used by contribution-checker subagents" )
50+ assert .Contains (t , text , `"jq *"` , "Workflow must allow jq payload construction for safeoutputs create_issue" )
51+
52+ lockPath := filepath .Join (repoRoot , ".github" , "workflows" , "contribution-check.lock.yml" )
53+ lockContent , err := os .ReadFile (lockPath )
54+ require .NoError (t , err , "Should read compiled contribution-check workflow" )
55+
56+ lockText := string (lockContent )
57+ for _ , token := range []string {
58+ "--allow-tool '\\ ''shell(git:*)'\\ ''" ,
59+ "--allow-tool '\\ ''shell(jq)'\\ ''" ,
60+ "--allow-tool '\\ ''shell(safeoutputs:*)'\\ ''" ,
61+ } {
62+ assert .Containsf (t , lockText , token , "Compiled workflow must contain %s" , token )
63+ }
64+ }
0 commit comments