Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ai-moderator.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/workflow/compiler_jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,7 @@ func (c *Compiler) buildActivationJob(data *WorkflowData, preActivationJobCreate

// Set permissions - activation job always needs contents:read for GitHub API access
// Also add reaction permissions if reaction is configured and not "none"
// Also add issues:write permission if lock-for-agent is enabled (for locking issues)
permsMap := map[PermissionScope]PermissionLevel{
PermissionContents: PermissionRead, // Always needed for GitHub API access to check file commits
}
Expand All @@ -1115,6 +1116,11 @@ func (c *Compiler) buildActivationJob(data *WorkflowData, preActivationJobCreate
permsMap[PermissionPullRequests] = PermissionWrite
}

// Add issues:write permission if lock-for-agent is enabled (even without reaction)
if data.LockForAgent {
permsMap[PermissionIssues] = PermissionWrite
}

perms := NewPermissionsFromMap(permsMap)
permissions := perms.RenderToYAML()

Expand Down
77 changes: 77 additions & 0 deletions pkg/workflow/lock_for_agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ Test workflow with lock-for-agent but no reaction.
if strings.Contains(yamlContent, "GH_AW_LOCK_FOR_AGENT: \"true\"") {
t.Error("Generated YAML should not set GH_AW_LOCK_FOR_AGENT env var without reaction step")
}

// Verify activation job has issues: write permission for locking
activationJobSection := extractJobSection(yamlContent, "activation")
if !strings.Contains(activationJobSection, "issues: write") {
t.Error("Activation job should have issues: write permission when lock-for-agent is enabled")
}

// Verify conclusion job has issues: write permission for unlocking
conclusionJobSection := extractJobSection(yamlContent, "conclusion")
if !strings.Contains(conclusionJobSection, "issues: write") {
t.Error("Conclusion job should have issues: write permission when lock-for-agent is enabled")
}
}

func TestLockForAgentDisabled(t *testing.T) {
Expand Down Expand Up @@ -204,6 +216,71 @@ Test workflow without lock-for-agent.
if strings.Contains(yamlContent, "GH_AW_LOCK_FOR_AGENT: \"true\"") {
t.Error("Generated YAML should not set GH_AW_LOCK_FOR_AGENT env var when lock-for-agent is disabled")
}

// Verify activation job has issues: write permission due to reaction (not lock-for-agent)
activationJobSection := extractJobSection(yamlContent, "activation")
if !strings.Contains(activationJobSection, "issues: write") {
t.Error("Activation job should have issues: write permission when reaction is enabled")
}
}

func TestLockForAgentDisabledWithoutReaction(t *testing.T) {
// Create temporary directory for test files
tmpDir := testutil.TempDir(t, "lock-disabled-no-reaction-test")

// Create a test markdown file without lock-for-agent and without reaction
testContent := `---
on:
issues:
types: [opened]
engine: copilot
safe-outputs:
add-comment: {}
---

# Test Without Lock For Agent and Without Reaction

Test workflow without lock-for-agent and without reaction.
`

testFile := filepath.Join(tmpDir, "test-no-lock-no-reaction.md")
if err := os.WriteFile(testFile, []byte(testContent), 0644); err != nil {
t.Fatal(err)
}

compiler := NewCompiler(false, "", "test")

// Parse the workflow
workflowData, err := compiler.ParseWorkflowFile(testFile)
if err != nil {
t.Fatalf("Failed to parse workflow: %v", err)
}

// Verify lock-for-agent field is false by default
if workflowData.LockForAgent {
t.Error("Expected LockForAgent to be false by default")
}

// Generate YAML and verify it does not contain lock/unlock steps
yamlContent, err := compiler.generateYAML(workflowData, testFile)
if err != nil {
t.Fatalf("Failed to generate YAML: %v", err)
}

// Lock and unlock steps should not be present
if strings.Contains(yamlContent, "Lock issue for agent workflow") {
t.Error("Generated YAML should not contain lock step when lock-for-agent is disabled")
}

if strings.Contains(yamlContent, "Unlock issue after agent workflow") {
t.Error("Generated YAML should not contain unlock step when lock-for-agent is disabled")
}

// Verify activation job does NOT have issues: write permission (no reaction and no lock-for-agent)
activationJobSection := extractJobSection(yamlContent, "activation")
if strings.Contains(activationJobSection, "issues: write") {
t.Error("Activation job should NOT have issues: write permission when lock-for-agent is disabled and no reaction is configured")
}
}

func TestLockForAgentOnPullRequest(t *testing.T) {
Expand Down