diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index ed2d8ed7a4..0adf7c151d 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -119,7 +119,6 @@ jobs: model: ${{ steps.generate_aw_info.outputs.model }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} - secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} steps: - name: Checkout actions folder uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 @@ -771,7 +770,6 @@ jobs: GH_AW_WORKFLOW_NAME: "Issue Classifier" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/smoke-opencode.lock.yml b/.github/workflows/smoke-opencode.lock.yml index 9264f7bf37..18721a1861 100644 --- a/.github/workflows/smoke-opencode.lock.yml +++ b/.github/workflows/smoke-opencode.lock.yml @@ -121,7 +121,6 @@ jobs: model: ${{ steps.generate_aw_info.outputs.model }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} - secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} steps: - name: Checkout actions folder uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 @@ -1494,7 +1493,6 @@ jobs: GH_AW_WORKFLOW_NAME: "Smoke OpenCode" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }} GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e 🚀 *[Liftoff Complete] — Powered by [{workflow_name}]({run_url})*\",\"runStarted\":\"🚀 **IGNITION!** [{workflow_name}]({run_url}) launching for this {event_type}! *[T-minus counting...]*\",\"runSuccess\":\"🎯 **MISSION SUCCESS** — [{workflow_name}]({run_url}) **TARGET ACQUIRED!** All systems nominal! ✨\",\"runFailure\":\"⚠️ **MISSION ABORT...** [{workflow_name}]({run_url}) {status}! Houston, we have a problem...\"}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/pkg/workflow/compiler_activation_jobs.go b/pkg/workflow/compiler_activation_jobs.go index 9a87da90a4..4fcb0e0cf4 100644 --- a/pkg/workflow/compiler_activation_jobs.go +++ b/pkg/workflow/compiler_activation_jobs.go @@ -711,8 +711,20 @@ func (c *Compiler) buildMainJob(data *WorkflowData, activationJobCreated bool) ( // Build job outputs // Always include model output for reuse in other jobs outputs := map[string]string{ - "model": "${{ steps.generate_aw_info.outputs.model }}", - "secret_verification_result": "${{ steps.validate-secret.outputs.verification_result }}", + "model": "${{ steps.generate_aw_info.outputs.model }}", + } + + // Only add secret_verification_result output if the engine adds the validate-secret step + // The validate-secret step is only added by engines that include it in GetInstallationSteps() + engine, err := c.getAgenticEngine(data.AI) + if err != nil { + return nil, fmt.Errorf("failed to get agentic engine: %w", err) + } + if EngineHasValidateSecretStep(engine, data) { + outputs["secret_verification_result"] = "${{ steps.validate-secret.outputs.verification_result }}" + compilerActivationJobsLog.Printf("Added secret_verification_result output (engine includes validate-secret step)") + } else { + compilerActivationJobsLog.Printf("Skipped secret_verification_result output (engine does not include validate-secret step)") } // Add safe-output specific outputs if the workflow uses the safe-outputs feature diff --git a/pkg/workflow/engine_helpers.go b/pkg/workflow/engine_helpers.go index a65c75013c..2936319310 100644 --- a/pkg/workflow/engine_helpers.go +++ b/pkg/workflow/engine_helpers.go @@ -441,3 +441,38 @@ func GetToolBinsEnvArg() []string { // Pre-wrap in double quotes so shellEscapeArg preserves them (allowing shell expansion) return []string{"--env", "\"GH_AW_TOOL_BINS=$GH_AW_TOOL_BINS\""} } + +// EngineHasValidateSecretStep checks if the engine's installation steps include the validate-secret step. +// This is used to determine whether the secret_verification_result job output should be added. +// +// The validate-secret step is only added by engines that include it in GetInstallationSteps(): +// - Copilot engine: Adds step when GetRequiredSecretNames returns non-empty +// - Claude engine: Adds step when GetRequiredSecretNames returns non-empty +// - Codex engine: Adds step when GetRequiredSecretNames returns non-empty +// - Custom engine: Never adds this step (returns empty from GetInstallationSteps) +// +// Implementation Note: +// This uses simple string matching which is acceptable because: +// - Installation steps are generated by our code, not user input +// - The "id: validate-secret" format is controlled by GenerateMultiSecretValidationStep() +// - GitHubActionStep is already a string slice, not structured YAML +// +// Parameters: +// - engine: The agentic engine to check +// - data: The workflow data (needed for GetInstallationSteps) +// +// Returns: +// - bool: true if the engine includes the validate-secret step, false otherwise +func EngineHasValidateSecretStep(engine CodingAgentEngine, data *WorkflowData) bool { + installSteps := engine.GetInstallationSteps(data) + for _, step := range installSteps { + for _, line := range step { + // String matching is safe here because installation steps are generated by our code + // and follow the format: " id: validate-secret" + if strings.Contains(line, "id: validate-secret") { + return true + } + } + } + return false +} diff --git a/pkg/workflow/notify_comment.go b/pkg/workflow/notify_comment.go index 9a3f5b2f19..6ea2962999 100644 --- a/pkg/workflow/notify_comment.go +++ b/pkg/workflow/notify_comment.go @@ -151,7 +151,16 @@ func (c *Compiler) buildConclusionJob(data *WorkflowData, mainJobName string, sa agentFailureEnvVars = append(agentFailureEnvVars, buildWorkflowMetadataEnvVarsWithTrackerID(data.Name, data.Source, data.TrackerID)...) agentFailureEnvVars = append(agentFailureEnvVars, " GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n") agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_AGENT_CONCLUSION: ${{ needs.%s.result }}\n", mainJobName)) - agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.%s.outputs.secret_verification_result }}\n", mainJobName)) + + // Only add secret_verification_result if the engine adds the validate-secret step + // The validate-secret step is only added by engines that include it in GetInstallationSteps() + engine, err := c.getAgenticEngine(data.AI) + if err != nil { + return nil, fmt.Errorf("failed to get agentic engine: %w", err) + } + if EngineHasValidateSecretStep(engine, data) { + agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.%s.outputs.secret_verification_result }}\n", mainJobName)) + } // Pass assignment error outputs from safe_outputs job if assign-to-agent is configured if data.SafeOutputs != nil && data.SafeOutputs.AssignToAgent != nil {