8000
Skip to content

feat: Add conditional workspace checkout to detection job for patch context#23961

Merged
lpcox merged 1 commit intomainfrom
copilot/detection-workspace-checkout
Apr 1, 2026
Merged

feat: Add conditional workspace checkout to detection job for patch context#23961
lpcox merged 1 commit intomainfrom
copilot/detection-workspace-checkout

Conversation

@lpcox
Copy link
Copy Markdown
Collaborator
@lpcox lpcox commented Apr 1, 2026

Summary

Adds a conditional actions/checkout step to the detection job that runs only when the agent produces a patch (has_patch == 'true'). This gives the threat detection engine access to the full repository codebase, enabling it to analyze code changes in context rather than in isolation.

Problem

The detection job runs on a fresh runner with no repository checkout. When a patch is present, the detection engine sees code changes entirely without context — it cannot see surrounding source files, existing patterns, dependency manifests, or project structure. This makes it difficult to distinguish legitimate changes from suspicious ones.

Solution

Conditional workspace checkout

  • New buildWorkspaceCheckoutForDetectionStep() method emits a checkout step with if: needs.agent.outputs.has_patch == 'true'
  • Uses actions/checkout with persist-credentials: false (security requirement)
  • Step is inserted after artifact download and before detection steps
  • Checks out the triggering SHA (pre-agent-changes state), which is the correct base for the patch

Always grant contents: read permission

  • Previously only granted in dev/script mode for the actions folder checkout
  • Now always granted since the workspace checkout requires it
  • contents: read is a minimal read-only permission — no security concern

Updated threat detection prompt

  • Added "Codebase Context" section instructing the engine to use $GITHUB_WORKSPACE when a patch is present
  • Directs the engine to review modified files in context, check dependency manifests, and inspect module structure
  • Both prompt copies synced (actions/setup/md/ and pkg/workflow/prompts/)

Tests

4 new unit tests:

  • TestWorkspaceCheckoutForDetectionStep — step present with correct condition, pin, and persist-credentials
  • TestDetectionJobAlwaysHasContentsRead — permissions include contents: read in production mode
  • TestWorkspaceCheckoutPresentWithCustomSteps — step present even when engine disabled but custom steps exist
  • TestWorkspaceCheckoutStepOrdering — step appears after artifact download and before detection guard

All existing tests continue to pass. 179 workflows recompiled.

Files changed

File Change
pkg/workflow/threat_detection.go New buildWorkspaceCheckoutForDetectionStep(), updated permissions logic
pkg/workflow/threat_detection_test.go 4 new tests
actions/setup/md/threat_detection.md Codebase context section
pkg/workflow/prompts/threat_detection.md Synced copy
168 .lock.yml files Recompiled with new step

Closes #23191

…ontext

When the agent produces a patch (has_patch == 'true'), the detection job
now checks out the target repository so the threat detection engine can
analyze code changes in the context of the surrounding codebase. This
allows the engine to distinguish legitimate patterns from suspicious ones
by examining existing dependencies, module structure, and calling code.

Changes:
- Add buildWorkspaceCheckoutForDetectionStep() that emits a conditional
  actions/checkout step with persist-credentials: false
- Always grant contents: read on the detection job (was previously only
  in dev/script mode) since the checkout requires it
- Update threat detection prompt template with codebase context section
  instructing the engine to use $GITHUB_WORKSPACE when a patch is present
- Add 4 unit tests covering step presence, permissions, ordering, and
  custom steps scenarios
- Recompile all 179 workflows and update wasm golden files

Closes #23191

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 1, 2026 22:14
@lpcox lpcox merged commit 2ee8ab4 into main Apr 1, 2026
94 checks passed
@lpcox lpcox deleted the copilot/detection-workspace-checkout branch April 1, 2026 22:18
Copy link
Copy Markdown
Contributor
Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a conditional actions/checkout in the threat detection job (only when needs.agent.outputs.has_patch == 'true') so the detection engine can analyze patches with full repository context, and updates the threat-detection prompt/docs accordingly.

Changes:

  • Add buildWorkspaceCheckoutForDetectionStep() and insert the conditional workspace checkout into the detection job step list.
  • Always grant contents: read permission to the detection job.
  • Update both threat-detection prompt copies to instruct the engine to use $GITHUB_WORKSPACE when a patch/bundle is present; recompile lock workflows to include the new step.

Reviewed changes

Copilot reviewed 172 out of 172 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/workflow/threat_detection.go Adds conditional workspace checkout and updates detection job permissions to always include contents: read.
pkg/workflow/threat_detection_test.go Adds tests asserting the checkout step presence/condition/order and contents permission.
pkg/workflow/prompts/threat_detection.md Documents using $GITHUB_WORKSPACE for contextual analysis when patch/bundle present.
actions/setup/md/threat_detection.md Syncs prompt documentation with the package copy.
.github/workflows/*.lock.yml Recompiled workflows to include the conditional checkout step (and permissions where applicable).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +551 to +567
// buildWorkspaceCheckoutForDetectionStep creates a checkout step for the detection job.
// It runs only when the agent job produced a patch, so the detection engine can
// analyze code changes in the context of the surrounding codebase.
func (c *Compiler) buildWorkspaceCheckoutForDetectionStep(data *WorkflowData) []string {
checkoutPin := GetActionPin("actions/checkout")
if checkoutPin == "" {
threatLog.Print("No action pin found for actions/checkout, skipping workspace checkout step")
return nil
}

steps := []string{
" - name: Checkout repository for patch context\n",
fmt.Sprintf(" if: needs.%s.outputs.has_patch == 'true'\n", constants.AgentJobName),
fmt.Sprintf(" uses: %s\n", checkoutPin),
" with:\n",
" persist-credentials: false\n",
}
Copy link
Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workspace checkout step is generated manually and ignores existing checkout configuration (WorkflowData.CheckoutConfigs / trial mode overrides) that the main agent job applies via CheckoutManager.GenerateDefaultCheckoutStep. If the agent job checked out a non-default repo/ref/token (or sparse checkout), the detection job will checkout a different workspace, so the threat detector may analyze the patch against the wrong codebase context. Consider generating this step via CheckoutManager.GenerateDefaultCheckoutStep (and then injecting the has_patch condition) so repo/ref/token/fetch-depth/sparse settings stay consistent with the agent job.

Copilot uses AI. Check for mistakes.
Comment on 8000 lines 595 to +611
// Add setup action steps (same as agent job - installs the agentic engine)
setupActionRef := c.resolveActionReference("./actions/setup", data)
if setupActionRef != "" || c.actionMode.IsScript() {
// For dev mode (local action path), checkout the actions folder first
steps = append(steps, c.generateCheckoutActionsFolder(data)...)
steps = append(steps, c.generateSetupStep(setupActionRef, SetupActionDestination, false)...)
}

// Download agent output artifact to access output files (prompt.txt, agent_output.json, patches).
// Use agent-downstream prefix since this job depends on the agent job.
agentArtifactPrefix := artifactPrefixExprForAgentDownstreamJob(data)
steps = append(steps, buildAgentOutputDownloadSteps(agentArtifactPrefix)...)

// Conditionally checkout the target repository so the detection engine can
// analyze patches in the context of the surrounding codebase.
steps = append(steps, c.buildWorkspaceCheckoutForDetectionStep(data)...)

Copy link
Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In dev mode, generateCheckoutActionsFolder() checks out github/gh-aw into the workspace so the local ./actions/setup can run. This new workspace checkout step will then overwrite the workspace with the target repo when has_patch is true, which can cause the runner to fail the Setup Scripts post-step (it won’t be able to find actions/setup/action.yml). Add a final "Restore actions folder" step (similar to compiler_yaml_main_job.go and compiler_safe_outputs_job.go) gated with always() so the post-step can complete after a root-level checkout.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add conditional workspace checkout to detection job for patch context

2 participants

0