This issue was posted by Claude Code using claude-fable-5-1 on behalf of David.
cc @pelikhan, following up on #50971 now that the pydantic-ai engine definition lives at pydantic/pydantic-ai-harness/gh-aw/pydantic.md@main.
What happens
Every run of a workflow that uses a custom engine and declares safe outputs ends with the detection job failing:
THREAT_DETECTION_STATUS: reason=config_error exit=2
Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.
##[error]ERR_SYSTEM: Detection result file not found at: /tmp/gh-aw/threat-detection/detection_result.json
The job is continue-on-error, so the run is green and the safe outputs are applied, with no threat detection having run. Example: https://github.com/dsfaccini/gh-aw-pydantic-ai-demo/actions/runs/34301598914 (compiler v0.88.2, threat-detect v0.5.1); the same annotation is on every run of that workflow.
Why
getThreatDetectionEngineID in pkg/workflow/threat_detection_external.go takes safe-outputs.threat-detection.engine when set and otherwise falls back to the workflow's own engine id, and the detection step runs threat-detect --engine <that id>. The binary's --engine accepts copilot, claude and codex (github/gh-aw-threat-detection README), so any custom engine id is a config_error.
Workarounds available to workflow authors
safe-outputs.threat-detection.engine: copilot (or another built-in), with that engine's credential in the repository.
safe-outputs.threat-detection.engine: false for no AI analysis.
Both need the author to know about the failure, and the green run hides it.
Suggested fix
Either of these would close the gap:
- When the workflow engine is not one the binary supports and
safe-outputs.threat-detection.engine is unset, fail at compile time with a message naming that key, or default detection to a built-in engine and say so in the compile output.
- Let an engine definition declare its detection engine in frontmatter, so a custom engine can ship a working default for its users.
Happy to take the second one on the pydantic-ai definition side once the frontmatter key exists.
cc @pelikhan, following up on #50971 now that the
pydantic-aiengine definition lives atpydantic/pydantic-ai-harness/gh-aw/pydantic.md@main.What happens
Every run of a workflow that uses a custom engine and declares safe outputs ends with the
detectionjob failing:The job is
continue-on-error, so the run is green and the safe outputs are applied, with no threat detection having run. Example: https://github.com/dsfaccini/gh-aw-pydantic-ai-demo/actions/runs/34301598914 (compiler v0.88.2,threat-detectv0.5.1); the same annotation is on every run of that workflow.Why
getThreatDetectionEngineIDinpkg/workflow/threat_detection_external.gotakessafe-outputs.threat-detection.enginewhen set and otherwise falls back to the workflow's own engine id, and the detection step runsthreat-detect --engine <that id>. The binary's--engineacceptscopilot,claudeandcodex(github/gh-aw-threat-detection README), so any custom engine id is aconfig_error.Workarounds available to workflow authors
safe-outputs.threat-detection.engine: copilot(or another built-in), with that engine's credential in the repository.safe-outputs.threat-detection.engine: falsefor no AI analysis.Both need the author to know about the failure, and the green run hides it.
Suggested fix
Either of these would close the gap:
safe-outputs.threat-detection.engineis unset, fail at compile time with a message naming that key, or default detection to a built-in engine and say so in the compile output.Happy to take the second one on the
pydantic-aidefinition side once the frontmatter key exists.