buildDetectionJobSteps builds the threat detection steps to be run in the separate detection job. These steps run after the agent job completes and analyze agent output for threats using the same agentic engine with sandbox.agent and fully blocked network. The detection job downloads the agent artif
(data *WorkflowData)
| 14 | // same agentic engine with sandbox.agent and fully blocked network. |
| 15 | // The detection job downloads the agent artifact to access the output files. |
| 16 | func (c *Compiler) buildDetectionJobSteps(data *WorkflowData) []string { |
| 17 | threatLog.Print("Building threat detection steps for detection job") |
| 18 | if data.SafeOutputs == nil || data.SafeOutputs.ThreatDetection == nil { |
| 19 | return nil |
| 20 | } |
| 21 | |
| 22 | var steps []string |
| 23 | |
| 24 | // Comment separator |
| 25 | steps = append(steps, " # --- Threat Detection ---\n") |
| 26 | |
| 27 | // Step 0: Clean stale firewall files left by the agent artifact download. |
| 28 | // The agent artifact populates sandbox/firewall/logs and sandbox/firewall/audit |
| 29 | // with files that cause the squid container to crash on start-up. |
| 30 | steps = append(steps, c.buildCleanFirewallDirsStep()...) |
| 31 | |
| 32 | // Step 1: Pull AWF container images - the detection engine runs inside AWF (firewall), |
| 33 | // so pre-pulling the containers speeds up execution and avoids on-demand pulls. |
| 34 | // |
| 35 | // For the inline Codex detection path (gh-aw-detection feature disabled), MCP setup |
| 36 | // generation already emits this step via generateDownloadDockerImagesStep, so skip here |
| 37 | // to avoid duplicate step names in the detection job. |
| 38 | // For the external detector path (gh-aw-detection: true), MCP setup is not called for |
| 39 | // the detection job, so the download step must be emitted here unconditionally. |
| 40 | usingExternalDetector := isFeatureEnabled(constants.GHAWDetectionFeatureFlag, data) |
| 41 | if c.getThreatDetectionEngineID(data) != "codex" || usingExternalDetector { |
| 42 | steps = append(steps, c.buildPullAWFContainersStep(data)...) |
| 43 | } |
| 44 | |
| 45 | // Step 2: Detection guard - determines whether detection should run |
| 46 | steps = append(steps, c.buildDetectionGuardStep()...) |
| 47 | |
| 48 | // Step 3: Clear MCP configuration files so the detection engine runs without MCP servers |
| 49 | steps = append(steps, c.buildClearMCPConfigStep()...) |
| 50 | |
| 51 | // Step 4: Prepare files - copies agent output files to expected paths |
| 52 | steps = append(steps, c.buildPrepareDetectionFilesStep()...) |
| 53 | |
| 54 | // Step 5: Custom pre-steps if configured (run before engine execution) |
| 55 | if len(data.SafeOutputs.ThreatDetection.Steps) > 0 { |
| 56 | steps = append(steps, c.buildCustomThreatDetectionSteps(data.SafeOutputs.ThreatDetection.Steps)...) |
| 57 | } |
| 58 | |
| 59 | // Step 6: Setup threat detection (github-script) |
| 60 | steps = append(steps, c.buildThreatDetectionAnalysisStep(data)...) |
| 61 | |
| 62 | if isFeatureEnabled(constants.GHAWDetectionFeatureFlag, data) { |
| 63 | // External detector path (features: gh-aw-detection: true) |
| 64 | |
| 65 | // Step 7: Install AWF binary (required for the detection AWF invocation) |
| 66 | steps = append(steps, c.buildInstallAWFForExternalDetectorStep(data)...) |
| 67 | |
| 68 | // Step 8: Install the selected agentic engine binary for threat-detect execution |
| 69 | steps = append(steps, c.buildInstallDetectionEngineForExternalDetectorStep(data)...) |
| 70 | |
| 71 | // Step 9: Prepare any engine-specific config files needed by threat-detect. |
| 72 | steps = append(steps, c.buildPrepareDetectionEngineConfigForExternalDetectorStep(data)...) |
| 73 |